<!-- markdownlint-disable MD013 MD033 -->
<!-- This file is generated by Paradox. Do not edit manually. -->

# @ankhorage/zora

![license: MIT](././paradox/badges/license.svg) ![npm: v21.0.14](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![docs: paradox](././paradox/badges/docs.svg)

Opinionated React Native and React Native Web UI kit built on @ankhorage/surface.

## Usage

### ZORA app root with optional runtime capabilities and adaptive UI.

Enable only the runtime capabilities the app uses. `toast` installs the host consumed by
`useToast()`. `bottomSheet` installs the native BottomSheet host; DatePicker and TimePicker use
that host on native and automatically use Popover on web.

Source: `examples/basic-app/App.tsx`

```tsx
import {
  AppBar,
  AppShell,
  BottomSheet,
  Button,
  DatePicker,
  Screen,
  ScreenSection,
  Text,
  TimePicker,
  useToast,
  View,
  ZoraProvider,
  type ZoraTheme,
} from '@ankhorage/zora';
import React from 'react';
import { GestureHandlerRootView } from 'react-native-gesture-handler';

const basicTheme: ZoraTheme = {
  id: 'basic-app',
  name: 'Basic app',
  appCategory: 'developer_tools',
  primaryColor: '#0b6e99',
  harmony: 'analogous',
};

export default function BasicApp() {
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <ZoraProvider
        bottomSheet
        initialMode="light"
        theme={basicTheme}
        toast={{ defaultDuration: 4000 }}
      >
        <AppShell header={<AppBar title="Dashboard" subtitle="Welcome to ZORA" />}>
          <Screen>
            <ScreenSection>
              <UsageContent />
            </ScreenSection>
          </Screen>
        </AppShell>
      </ZoraProvider>
    </GestureHandlerRootView>
  );
}

/*** Demonstrates toast feedback and adaptive picker presentation. */
function UsageContent() {
  const { showToast } = useToast();
  const [date, setDate] = React.useState<string | null>(null);
  const [time, setTime] = React.useState<string | null>(null);

  return (
    <View gap="m">
      <Text variant="lead">Runtime capabilities are opt-in at the app root.</Text>
      <Button
        onPress={() =>
          showToast({
            description: 'ToastProvider is installed by ZoraProvider.',
            status: 'success',
            title: 'Saved',
          })
        }
      >
        Show toast
      </Button>
      <DatePicker label="Date" onValueChange={setDate} value={date} />
      <TimePicker label="Time" onValueChange={setTime} value={time} />
    </View>
  );
}

/***
 * Direct native BottomSheet usage.
 *
 * Render this inside `<ZoraProvider bottomSheet>` on native. Web pickers do not need this host;
 * their platform adapters use Popover instead.
 *
 * @usage
 * @readme
 */
export function NativeBottomSheetExample() {
  const [open, setOpen] = React.useState(false);

  return (
    <View gap="m">
      <Button onPress={() => setOpen(true)}>Open native bottom sheet</Button>
      <BottomSheet onDismiss={() => setOpen(false)} open={open}>
        <View gap="s" p="m">
          <Text variant="label">Bottom sheet content</Text>
          <Button onPress={() => setOpen(false)} variant="ghost">
            Close
          </Button>
        </View>
      </BottomSheet>
    </View>
  );
}
```

### Direct native BottomSheet usage.

Render this inside `<ZoraProvider bottomSheet>` on native. Web pickers do not need this host;
their platform adapters use Popover instead.

Source: `examples/basic-app/App.tsx`

```tsx
import {
  AppBar,
  AppShell,
  BottomSheet,
  Button,
  DatePicker,
  Screen,
  ScreenSection,
  Text,
  TimePicker,
  useToast,
  View,
  ZoraProvider,
  type ZoraTheme,
} from '@ankhorage/zora';
import React from 'react';
import { GestureHandlerRootView } from 'react-native-gesture-handler';

const basicTheme: ZoraTheme = {
  id: 'basic-app',
  name: 'Basic app',
  appCategory: 'developer_tools',
  primaryColor: '#0b6e99',
  harmony: 'analogous',
};

/***
 * ZORA app root with optional runtime capabilities and adaptive UI.
 *
 * Enable only the runtime capabilities the app uses. `toast` installs the host consumed by
 * `useToast()`. `bottomSheet` installs the native BottomSheet host; DatePicker and TimePicker use
 * that host on native and automatically use Popover on web.
 *
 * @usage
 * @readme
 */
export default function BasicApp() {
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <ZoraProvider
        bottomSheet
        initialMode="light"
        theme={basicTheme}
        toast={{ defaultDuration: 4000 }}
      >
        <AppShell header={<AppBar title="Dashboard" subtitle="Welcome to ZORA" />}>
          <Screen>
            <ScreenSection>
              <UsageContent />
            </ScreenSection>
          </Screen>
        </AppShell>
      </ZoraProvider>
    </GestureHandlerRootView>
  );
}

/*** Demonstrates toast feedback and adaptive picker presentation. */
function UsageContent() {
  const { showToast } = useToast();
  const [date, setDate] = React.useState<string | null>(null);
  const [time, setTime] = React.useState<string | null>(null);

  return (
    <View gap="m">
      <Text variant="lead">Runtime capabilities are opt-in at the app root.</Text>
      <Button
        onPress={() =>
          showToast({
            description: 'ToastProvider is installed by ZoraProvider.',
            status: 'success',
            title: 'Saved',
          })
        }
      >
        Show toast
      </Button>
      <DatePicker label="Date" onValueChange={setDate} value={date} />
      <TimePicker label="Time" onValueChange={setTime} value={time} />
    </View>
  );
}

export function NativeBottomSheetExample() {
  const [open, setOpen] = React.useState(false);

  return (
    <View gap="m">
      <Button onPress={() => setOpen(true)}>Open native bottom sheet</Button>
      <BottomSheet onDismiss={() => setOpen(false)} open={open}>
        <View gap="s" p="m">
          <Text variant="label">Bottom sheet content</Text>
          <Button onPress={() => setOpen(false)} variant="ghost">
            Close
          </Button>
        </View>
      </BottomSheet>
    </View>
  );
}
```

## Generated documentation

- [Interactive documentation app](././paradox/index.html)
- [Public API reference](././paradox/exports.md)
- [Component registry](././paradox/components.md)
- [Architecture overview](././paradox/diagrams/architecture-overview.mmd)
- [Module relationships](././paradox/diagrams/module-relationships.mmd)
- [Export graph](././paradox/diagrams/export-graph.mmd)
- [createZoraThemeConfig sequence](././paradox/diagrams/sequences/create-zora-theme-config.mmd)
- [resolveAvatarInitials sequence](././paradox/diagrams/sequences/resolve-avatar-initials.mmd)
- [resolveOAuthProviderIcon sequence](././paradox/diagrams/sequences/resolve-oauth-provider-icon.mmd)
- [resolveOAuthProviderLabel sequence](././paradox/diagrams/sequences/resolve-oauth-provider-label.mmd)
- [SelectableItem sequence](././paradox/diagrams/sequences/selectable-item.mmd)
- [SelectionProvider sequence](././paradox/diagrams/sequences/selection-provider.mmd)
- [ThemeModeToggle sequence](././paradox/diagrams/sequences/theme-mode-toggle.mmd)
- [useZoraTheme sequence](././paradox/diagrams/sequences/use-zora-theme.mmd)
- [validateField sequence](././paradox/diagrams/sequences/validate-field.mmd)
- [validateFields sequence](././paradox/diagrams/sequences/validate-fields.mmd)
- [validateUploadAsset sequence](././paradox/diagrams/sequences/validate-upload-asset.mmd)
- [validateValue sequence](././paradox/diagrams/sequences/validate-value.mmd)
