@3gs/ui 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +43 -0
- package/dist/components/ActionSheet/ActionSheet.d.ts +40 -0
- package/dist/components/ActionSheet/index.d.ts +2 -0
- package/dist/components/Alert/Alert.d.ts +36 -0
- package/dist/components/Alert/index.d.ts +2 -0
- package/dist/components/Badge/Badge.d.ts +13 -0
- package/dist/components/Badge/index.d.ts +2 -0
- package/dist/components/Button/Button.d.ts +32 -0
- package/dist/components/Button/index.d.ts +2 -0
- package/dist/components/DatePicker/DatePicker.d.ts +57 -0
- package/dist/components/DatePicker/index.d.ts +2 -0
- package/dist/components/HUD/HUD.d.ts +56 -0
- package/dist/components/HUD/index.d.ts +2 -0
- package/dist/components/Icon/Icon.d.ts +27 -0
- package/dist/components/Icon/index.d.ts +2 -0
- package/dist/components/Keyboard/Keyboard.d.ts +38 -0
- package/dist/components/Keyboard/index.d.ts +2 -0
- package/dist/components/List/List.d.ts +55 -0
- package/dist/components/List/index.d.ts +2 -0
- package/dist/components/ModalSheet/ModalSheet.d.ts +36 -0
- package/dist/components/ModalSheet/index.d.ts +2 -0
- package/dist/components/NavigationBar/NavigationBar.d.ts +41 -0
- package/dist/components/NavigationBar/index.d.ts +2 -0
- package/dist/components/NotificationBanner/NotificationBanner.d.ts +50 -0
- package/dist/components/NotificationBanner/index.d.ts +2 -0
- package/dist/components/PageControl/PageControl.d.ts +32 -0
- package/dist/components/PageControl/index.d.ts +2 -0
- package/dist/components/Picker/Picker.d.ts +45 -0
- package/dist/components/Picker/index.d.ts +2 -0
- package/dist/components/Popover/Popover.d.ts +40 -0
- package/dist/components/Popover/index.d.ts +2 -0
- package/dist/components/Progress/Progress.d.ts +37 -0
- package/dist/components/Progress/index.d.ts +2 -0
- package/dist/components/SearchBar/SearchBar.d.ts +61 -0
- package/dist/components/SearchBar/index.d.ts +2 -0
- package/dist/components/SegmentedControl/SegmentedControl.d.ts +50 -0
- package/dist/components/SegmentedControl/index.d.ts +2 -0
- package/dist/components/Slider/Slider.d.ts +39 -0
- package/dist/components/Slider/index.d.ts +2 -0
- package/dist/components/StatusBar/StatusBar.d.ts +24 -0
- package/dist/components/StatusBar/index.d.ts +2 -0
- package/dist/components/Stepper/Stepper.d.ts +55 -0
- package/dist/components/Stepper/index.d.ts +2 -0
- package/dist/components/Switch/Switch.d.ts +26 -0
- package/dist/components/Switch/index.d.ts +2 -0
- package/dist/components/TabBar/TabBar.d.ts +33 -0
- package/dist/components/TabBar/index.d.ts +2 -0
- package/dist/components/TextField/TextField.d.ts +38 -0
- package/dist/components/TextField/index.d.ts +2 -0
- package/dist/components/Toolbar/Toolbar.d.ts +58 -0
- package/dist/components/Toolbar/index.d.ts +2 -0
- package/dist/index.cjs +73 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +2803 -0
- package/dist/lib/cn.d.ts +2 -0
- package/dist/lib/i18n.d.ts +89 -0
- package/dist/ui.css +1 -0
- package/package.json +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Timon Franke
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# @3gs/ui
|
|
2
|
+
|
|
3
|
+
React components in the **iPhone 3GS / iOS 3** style — glossy gel
|
|
4
|
+
skeuomorphism, dark by default, with the classic blue-gray light theme one
|
|
5
|
+
attribute away. Icons via [lucide](https://lucide.dev), tinted through an SVG
|
|
6
|
+
gradient so they get the same glass.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pnpm add @3gs/ui lucide-react
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
import "@3gs/ui/styles.css";
|
|
14
|
+
import { NavigationBar, BarButton, List, ListItem, TabBar, TabBarItem, Icon } from "@3gs/ui";
|
|
15
|
+
import { Gamepad2, Star, LayoutGrid } from "lucide-react";
|
|
16
|
+
|
|
17
|
+
export function Screen() {
|
|
18
|
+
return (
|
|
19
|
+
<div className="gs-root">
|
|
20
|
+
<NavigationBar title="Categories" left={<BarButton variant="back">Featured</BarButton>} />
|
|
21
|
+
<List>
|
|
22
|
+
<ListItem iconTile iconTint="red" icon={<Icon icon={Gamepad2} variant="flat" size={18} />} title="Games" accessory="chevron" onClick={…} />
|
|
23
|
+
</List>
|
|
24
|
+
<TabBar defaultValue="featured">
|
|
25
|
+
<TabBarItem value="featured" icon={Star} label="Featured" />
|
|
26
|
+
<TabBarItem value="categories" icon={LayoutGrid} label="Categories" badge={43} />
|
|
27
|
+
</TabBar>
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- **Themes:** wrap in `.gs-root` (dark) or `.gs-root[data-theme="light"]`.
|
|
34
|
+
- **Tokens:** every colour, gel gradient, rim, radius and size is a `--gs-*`
|
|
35
|
+
custom property; override on `.gs-root` to retint.
|
|
36
|
+
- **Components:** Button, Switch, TextField / SearchField, NavigationBar /
|
|
37
|
+
BarButton, TabBar, List, Alert, SegmentedControl, Slider, ActionSheet,
|
|
38
|
+
Picker, DatePicker, ProgressBar / ActivityIndicator, StatusBar, Toolbar,
|
|
39
|
+
PageControl, Popover, HUD, Keyboard, ModalSheet, Stepper, SearchBar,
|
|
40
|
+
NotificationBanner, plus the `Icon` and `Badge` foundation.
|
|
41
|
+
- **Peer deps:** React 18 or 19.
|
|
42
|
+
|
|
43
|
+
Showcase, tokens gallery and source: https://github.com/TimonBozzApps/design-system-3gs
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export interface ActionSheetAction {
|
|
3
|
+
label: string;
|
|
4
|
+
onClick?: () => void;
|
|
5
|
+
/** light silver glass with dark text (default) or red gel. */
|
|
6
|
+
variant?: "default" | "destructive";
|
|
7
|
+
/**
|
|
8
|
+
* `true` keeps the sheet open after the click (the caller decides when to
|
|
9
|
+
* close). Default: the action fires `onClick`, then `onClose`.
|
|
10
|
+
*/
|
|
11
|
+
keepOpen?: boolean;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface ActionSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
|
|
15
|
+
open: boolean;
|
|
16
|
+
/** Small gray centered text at the top of the sheet. */
|
|
17
|
+
title?: ReactNode;
|
|
18
|
+
/** Stacked in order, top to bottom. */
|
|
19
|
+
actions: ActionSheetAction[];
|
|
20
|
+
/** Label of the dark Cancel button at the bottom. Default `strings.cancel` ("Cancel"); `null` hides it. */
|
|
21
|
+
cancelLabel?: string | null;
|
|
22
|
+
/** Called after any action, on Cancel, on Escape, and on backdrop click when `dismissOnBackdrop`. */
|
|
23
|
+
onClose?: () => void;
|
|
24
|
+
/** Default `true` — tapping the dimmed area behind the sheet dismisses it. */
|
|
25
|
+
dismissOnBackdrop?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Default `false` → portal to `document.body` with a `position: fixed` backdrop.
|
|
28
|
+
* `true` → render in place with `position: absolute; inset: 0`, filling the
|
|
29
|
+
* nearest positioned ancestor (e.g. a phone screen in a showcase).
|
|
30
|
+
*/
|
|
31
|
+
contained?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The iOS 3 action sheet (`UIActionSheet`): a translucent black-glass sheet
|
|
35
|
+
* that slides up from the bottom, a small gray title and a stack of full-width
|
|
36
|
+
* 46 px gel buttons — light silver glass for normal actions, red gel for the
|
|
37
|
+
* destructive one and a dark "Cancel" at the bottom. Renders nothing while
|
|
38
|
+
* `open` is false. The ref points at the sheet panel.
|
|
39
|
+
*/
|
|
40
|
+
export declare const ActionSheet: import('react').ForwardRefExoticComponent<ActionSheetProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export interface AlertAction {
|
|
3
|
+
label: string;
|
|
4
|
+
onClick?: () => void;
|
|
5
|
+
/** dark navy gel (default), light glass (primary — the highlighted "OK") or red gel. */
|
|
6
|
+
variant?: "default" | "primary" | "destructive";
|
|
7
|
+
/**
|
|
8
|
+
* `true` keeps the alert open after the click (the caller decides when to
|
|
9
|
+
* close). Default: the action fires `onClick`, then `onClose`.
|
|
10
|
+
*/
|
|
11
|
+
keepOpen?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
|
|
14
|
+
open: boolean;
|
|
15
|
+
title: ReactNode;
|
|
16
|
+
message?: ReactNode;
|
|
17
|
+
/** 1..n actions. Exactly two render side by side, any other count stacks. */
|
|
18
|
+
actions: AlertAction[];
|
|
19
|
+
/** Called after an action, on Escape, and on backdrop click when `dismissOnBackdrop`. */
|
|
20
|
+
onClose?: () => void;
|
|
21
|
+
/** Default `false` — iOS 3 alerts were strictly modal. */
|
|
22
|
+
dismissOnBackdrop?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Default `false` → portal to `document.body` with a `position: fixed` backdrop.
|
|
25
|
+
* `true` → render in place with `position: absolute; inset: 0`, filling the
|
|
26
|
+
* nearest positioned ancestor (e.g. a phone screen in a showcase).
|
|
27
|
+
*/
|
|
28
|
+
contained?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The iOS 3 modal alert (`UIAlertView`): a deep-blue glass dialog with a thick
|
|
32
|
+
* translucent white border, an elliptical top gloss, bold centered white title
|
|
33
|
+
* and 43 px gel buttons. Pops in with a slight overshoot. Renders nothing while
|
|
34
|
+
* `open` is false. The ref points at the dialog panel.
|
|
35
|
+
*/
|
|
36
|
+
export declare const Alert: import('react').ForwardRefExoticComponent<AlertProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
export interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
|
|
3
|
+
/** Number or short text. Numbers above `max` render as `max+`. */
|
|
4
|
+
value?: number | string;
|
|
5
|
+
max?: number;
|
|
6
|
+
/** Red gel (default) or the quieter gray used inside list cells. */
|
|
7
|
+
tone?: "red" | "gray";
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The classic red gel badge (unread counts on tab-bar icons, app icons).
|
|
11
|
+
* Renders nothing when `value` is `0`, `""` or undefined.
|
|
12
|
+
*/
|
|
13
|
+
export declare const Badge: import('react').ForwardRefExoticComponent<BadgeProps & import('react').RefAttributes<HTMLSpanElement>>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ButtonHTMLAttributes } from 'react';
|
|
2
|
+
import { LucideIcon } from 'lucide-react';
|
|
3
|
+
export type ButtonVariant =
|
|
4
|
+
/** dark gel — the everyday button */
|
|
5
|
+
"default"
|
|
6
|
+
/** blue gel — the "Done" / confirm button */
|
|
7
|
+
| "primary"
|
|
8
|
+
/** red gel — "Delete Contact", "Sign Out" style */
|
|
9
|
+
| "destructive";
|
|
10
|
+
export type ButtonSize =
|
|
11
|
+
/** 30 px tall, 13 px text — nav-bar / toolbar size */
|
|
12
|
+
"sm"
|
|
13
|
+
/** 44 px tall, 17 px text — the standard touch target (default) */
|
|
14
|
+
| "md"
|
|
15
|
+
/** 50 px tall, 18 px text — prominent CTA */
|
|
16
|
+
| "lg";
|
|
17
|
+
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
18
|
+
variant?: ButtonVariant;
|
|
19
|
+
size?: ButtonSize;
|
|
20
|
+
/** Full width — the grouped-table "Delete Contact" / "Sign Out" style. */
|
|
21
|
+
block?: boolean;
|
|
22
|
+
/** Any `lucide-react` icon, rendered flat in white next to the label. */
|
|
23
|
+
icon?: LucideIcon;
|
|
24
|
+
/** Which side of the label the icon sits on. Default: `leading`. */
|
|
25
|
+
iconPosition?: "leading" | "trailing";
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The iOS 3 gel push button: a vertical gradient with a hard highlight split
|
|
29
|
+
* at 50 %, a 1 px black outline with a light inner rim, and bold white text
|
|
30
|
+
* with a dark text-shadow. Pressing removes the gloss and sinks the gel.
|
|
31
|
+
*/
|
|
32
|
+
export declare const Button: import('react').ForwardRefExoticComponent<ButtonProps & import('react').RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
import { PickerValue } from '../Picker';
|
|
3
|
+
export type DatePickerMode = "date" | "time" | "dateTime";
|
|
4
|
+
export interface DatePickerProps extends Omit<HTMLAttributes<HTMLDivElement>, "onChange" | "defaultValue"> {
|
|
5
|
+
/** Which `UIDatePicker` preset. Default `date`. */
|
|
6
|
+
mode?: DatePickerMode;
|
|
7
|
+
/** Controlled value. */
|
|
8
|
+
value?: Date;
|
|
9
|
+
/** Uncontrolled initial value. Default: now, minutes rounded to `minuteInterval`. */
|
|
10
|
+
defaultValue?: Date;
|
|
11
|
+
onChange?: (date: Date) => void;
|
|
12
|
+
/** Step of the minute drum. Default `1`. */
|
|
13
|
+
minuteInterval?: 1 | 5 | 10 | 15 | 30;
|
|
14
|
+
/** `h12` (1–12 plus an AM/PM drum, default) or `h23` (0–23). */
|
|
15
|
+
hourCycle?: "h12" | "h23";
|
|
16
|
+
/** Years offered by the `date` preset, inclusive. Default `[1970, 2037]`. */
|
|
17
|
+
yearRange?: [number, number];
|
|
18
|
+
/** `dateTime` preset: days before and after the initial value in the rolling day drum. Default `365`. */
|
|
19
|
+
dayRange?: number;
|
|
20
|
+
/** Intl locale for month, weekday and AM/PM names. Default: the `<GsProvider>` locale, else `en-US`. */
|
|
21
|
+
locale?: string;
|
|
22
|
+
/** Visible rows per drum. Default `5`. */
|
|
23
|
+
rows?: 3 | 5 | 7;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
/** `aria-label` for the picker. Default: `strings.date` / `time` / `dateTime` per `mode`. */
|
|
26
|
+
label?: string;
|
|
27
|
+
}
|
|
28
|
+
/** Days in `month` (1–12) of `year`. */
|
|
29
|
+
export declare function daysInMonth(month: number, year: number): number;
|
|
30
|
+
/** Local calendar date as `yyyy-mm-dd` — the stable option value of the rolling day drum. */
|
|
31
|
+
export declare function toISODate(date: Date): string;
|
|
32
|
+
/**
|
|
33
|
+
* Copy of `date` with seconds zeroed and minutes rounded to the nearest
|
|
34
|
+
* multiple of `interval` (`:58` at interval 5 carries into the next hour).
|
|
35
|
+
*/
|
|
36
|
+
export declare function roundToInterval(date: Date, interval: number): Date;
|
|
37
|
+
/**
|
|
38
|
+
* The drum selection that shows `date`:
|
|
39
|
+
* `date` → `{ month, day, year }` · `time` → `{ hour, minute, period? }` ·
|
|
40
|
+
* `dateTime` → `{ day: "yyyy-mm-dd", hour, minute, period? }`
|
|
41
|
+
* (`period` only with `hourCycle="h12"`; numbers are unpadded decimal strings).
|
|
42
|
+
*/
|
|
43
|
+
export declare function dateToValue(date: Date, mode: DatePickerMode, hourCycle: "h12" | "h23"): PickerValue;
|
|
44
|
+
/**
|
|
45
|
+
* A new `Date` built from a drum selection. Fields the preset has no drum for
|
|
46
|
+
* are copied from `base`; seconds are zeroed; a day past the end of the month
|
|
47
|
+
* (Feb 30) is clamped to the month's last day.
|
|
48
|
+
*/
|
|
49
|
+
export declare function valueToDate(value: PickerValue, base: Date, mode: DatePickerMode, hourCycle: "h12" | "h23"): Date;
|
|
50
|
+
/**
|
|
51
|
+
* `UIDatePicker`: the three date-and-time presets built on `Picker`'s drums —
|
|
52
|
+
* `date` (Month · Day · Year), `time` (Hour · Minute · AM/PM) and `dateTime`
|
|
53
|
+
* (a rolling "Today" / "Mon Jun 29" day drum · Hour · Minute · AM/PM). Works
|
|
54
|
+
* in local time; the day drum shrinks with the selected month and a day that
|
|
55
|
+
* no longer fits (Feb 30) is clamped and reported.
|
|
56
|
+
*/
|
|
57
|
+
export declare const DatePicker: import('react').ForwardRefExoticComponent<DatePickerProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export type HUDKind =
|
|
3
|
+
/** 37 px white spinner — "Loading…" (default) */
|
|
4
|
+
"loading"
|
|
5
|
+
/** a gel progress bar driven by `progress` */
|
|
6
|
+
| "progress"
|
|
7
|
+
/** big white check — "Saved" */
|
|
8
|
+
| "success"
|
|
9
|
+
/** big white X — "Failed" */
|
|
10
|
+
| "error"
|
|
11
|
+
/** label only: a compact pill-ish toast — "Copied" */
|
|
12
|
+
| "text"
|
|
13
|
+
/** your own graphic in the `icon` slot — the volume bell */
|
|
14
|
+
| "custom";
|
|
15
|
+
export interface HUDProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
|
|
16
|
+
open: boolean;
|
|
17
|
+
/** What the square shows. Default `loading`. */
|
|
18
|
+
kind?: HUDKind;
|
|
19
|
+
/** Bold 16 px white label under the graphic ("Loading…", "Saved"). */
|
|
20
|
+
title?: ReactNode;
|
|
21
|
+
/** Optional 13 px secondary line. */
|
|
22
|
+
message?: ReactNode;
|
|
23
|
+
/** `0..100` for `kind="progress"`. Omit for an indeterminate bar. */
|
|
24
|
+
progress?: number;
|
|
25
|
+
/** The graphic for `kind="custom"`, e.g. `<Icon icon={Volume2} variant="flat" size={48} />`. */
|
|
26
|
+
icon?: ReactNode;
|
|
27
|
+
/**
|
|
28
|
+
* Auto-dismiss: calls `onClose` after this many ms. The timer restarts when
|
|
29
|
+
* `open`, `title` or `kind` change, so a toast that swaps its text stays up
|
|
30
|
+
* for the full duration again. Typical toast use: 1500.
|
|
31
|
+
*/
|
|
32
|
+
duration?: number;
|
|
33
|
+
onClose?: () => void;
|
|
34
|
+
/** Default `center`; `top` / `bottom` sit 60 px from that edge. */
|
|
35
|
+
position?: "center" | "top" | "bottom";
|
|
36
|
+
/**
|
|
37
|
+
* Default `false`: pointer events pass through the transparent backdrop —
|
|
38
|
+
* the HUD is a non-modal overlay. `true`: the backdrop absorbs clicks (still
|
|
39
|
+
* no dimming, HUDs never dimmed) and the box reports `aria-busy`.
|
|
40
|
+
*/
|
|
41
|
+
blocking?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Default `false` → portal to `document.body` with a `position: fixed` backdrop.
|
|
44
|
+
* `true` → render in place with `position: absolute; inset: 0`, filling the
|
|
45
|
+
* nearest positioned ancestor (e.g. a phone screen in a showcase).
|
|
46
|
+
*/
|
|
47
|
+
contained?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The iOS 3 progress HUD: a ~140 px rounded translucent black square with a
|
|
51
|
+
* big spinner, a check mark, a progress bar or a custom glyph and a short
|
|
52
|
+
* white label — this era's toast ("Loading…", "Saved", the ringer bell).
|
|
53
|
+
* Non-modal by default, optionally auto-dismissing. Renders nothing while
|
|
54
|
+
* `open` is false. The ref points at the box.
|
|
55
|
+
*/
|
|
56
|
+
export declare const HUD: import('react').ForwardRefExoticComponent<HUDProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { LucideIcon, LucideProps } from 'lucide-react';
|
|
2
|
+
export type IconVariant =
|
|
3
|
+
/** gray glass — inactive tab icons, list glyphs */
|
|
4
|
+
"gloss"
|
|
5
|
+
/** blue glass — the active/tinted state */
|
|
6
|
+
| "active"
|
|
7
|
+
/** plain currentColor stroke, no gel treatment */
|
|
8
|
+
| "flat";
|
|
9
|
+
export interface IconProps extends Omit<LucideProps, "ref"> {
|
|
10
|
+
/** Any `lucide-react` icon component, e.g. `Star`, `Search`, `Settings`. */
|
|
11
|
+
icon: LucideIcon;
|
|
12
|
+
variant?: IconVariant;
|
|
13
|
+
/** Adds the etched drop-shadow that sits icons into a bar. Default: true for gel variants. */
|
|
14
|
+
embossed?: boolean;
|
|
15
|
+
size?: number | string;
|
|
16
|
+
/** Accessible label. Omit to mark the icon decorative (`aria-hidden`). */
|
|
17
|
+
label?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Glossy icon wrapper around lucide-react.
|
|
21
|
+
*
|
|
22
|
+
* The iOS 3 "gel" look: a vertical gradient with a hard split at 50% —
|
|
23
|
+
* lighter on top, deeper below — applied through the icon's stroke.
|
|
24
|
+
* The `<linearGradient>` is inlined inside every SVG so the component
|
|
25
|
+
* works without a global defs sheet (identical ids are harmless).
|
|
26
|
+
*/
|
|
27
|
+
export declare const Icon: import('react').ForwardRefExoticComponent<IconProps & import('react').RefAttributes<SVGSVGElement>>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
export type KeyboardLayer = "letters" | "numbers" | "symbols";
|
|
3
|
+
export type KeyboardReturnKey = "return" | "Go" | "Search" | "Done" | "Send" | "Next";
|
|
4
|
+
export interface KeyboardProps extends Omit<HTMLAttributes<HTMLDivElement>, "onChange" | "autoCapitalize"> {
|
|
5
|
+
/** High-level binding: the keyboard edits this string (append / backspace) and reports the result. */
|
|
6
|
+
value?: string;
|
|
7
|
+
onChange?: (value: string) => void;
|
|
8
|
+
/** Low-level: a character, `" "` for space, `"\n"` for return. Fired in addition to `onChange`. */
|
|
9
|
+
onKey?: (key: string) => void;
|
|
10
|
+
onBackspace?: () => void;
|
|
11
|
+
onReturn?: () => void;
|
|
12
|
+
/**
|
|
13
|
+
* The return key's type (`UIReturnKeyType`). Anything but `"return"` renders as the blue gel key.
|
|
14
|
+
* The visible text is looked up in the provider strings (`return`, `go`, `search`, `done`, `send`, `next`).
|
|
15
|
+
*/
|
|
16
|
+
returnKey?: KeyboardReturnKey;
|
|
17
|
+
/** Controlled layer. Leave undefined to let the keyboard manage its own, starting at `"letters"`. */
|
|
18
|
+
layer?: KeyboardLayer;
|
|
19
|
+
onLayerChange?: (layer: KeyboardLayer) => void;
|
|
20
|
+
/** Start with shift on (sentence start). Default `false`. */
|
|
21
|
+
defaultShift?: boolean;
|
|
22
|
+
/** Shift auto-enables on an empty value or after `". "`. Only acts through the `value`/`onChange` binding. */
|
|
23
|
+
autoCapitalize?: boolean;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
/** Accessible name (`aria-label`). Default `strings.keyboard` ("Keyboard"). */
|
|
26
|
+
label?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The iOS 3 on-screen keyboard in its dark "alert" appearance
|
|
30
|
+
* (`UIKeyboardAppearanceAlert`): 320×216, dark gel letter keys, darker
|
|
31
|
+
* function keys, and the enlarged popup bubble above the key being pressed.
|
|
32
|
+
*
|
|
33
|
+
* Keys are real buttons. Every key cancels `pointerdown`/`mousedown` so a
|
|
34
|
+
* focused text field elsewhere on the page keeps its focus (and caret) while
|
|
35
|
+
* the user types here; the key commits on `click`, so keyboard activation
|
|
36
|
+
* (Tab + Enter/Space) works too.
|
|
37
|
+
*/
|
|
38
|
+
export declare const Keyboard: import('react').ForwardRefExoticComponent<KeyboardProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { HTMLAttributes, MouseEventHandler, ReactNode } from 'react';
|
|
2
|
+
export interface ListProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
/** `grouped` (rounded, outlined container on the pinstripe) or `plain` (full-bleed rows). */
|
|
4
|
+
variant?: "grouped" | "plain";
|
|
5
|
+
/** Section header above the group — bold gray, etched. */
|
|
6
|
+
header?: ReactNode;
|
|
7
|
+
/** Small centered gray text under the group. */
|
|
8
|
+
footer?: ReactNode;
|
|
9
|
+
/** `<ListItem>`s. */
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The grouped table view: a rounded, black-outlined container of cells sitting
|
|
14
|
+
* on the pinstripe background, with an optional section header and footer.
|
|
15
|
+
* `variant="plain"` drops the container for edge-to-edge rows.
|
|
16
|
+
*/
|
|
17
|
+
export declare const List: import('react').ForwardRefExoticComponent<ListProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
18
|
+
export type ListItemAccessory =
|
|
19
|
+
/** gray disclosure chevron — "tap to drill in" */
|
|
20
|
+
"chevron"
|
|
21
|
+
/** blue check — the chosen option in a picker list */
|
|
22
|
+
| "checkmark"
|
|
23
|
+
/** blue circled chevron — the detail-disclosure button */
|
|
24
|
+
| "detail" | "none";
|
|
25
|
+
export interface ListItemProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
|
|
26
|
+
/** Anything, typically `<Icon icon={Star} />`; rendered inside a 29 × 29 slot. */
|
|
27
|
+
icon?: ReactNode;
|
|
28
|
+
/** Draw the icon slot as a glossy app-icon tile (29 × 29, radius 6, black outline). */
|
|
29
|
+
iconTile?: boolean;
|
|
30
|
+
/** Tile gel colour. Default `gray`. */
|
|
31
|
+
iconTint?: "gray" | "blue" | "red";
|
|
32
|
+
/** Bold white cell title. Ellipsises. */
|
|
33
|
+
title: ReactNode;
|
|
34
|
+
/** Secondary gray line under the title. Ellipsises. */
|
|
35
|
+
subtitle?: ReactNode;
|
|
36
|
+
/** Right-aligned blue value text, e.g. "On", "3 items". */
|
|
37
|
+
detail?: ReactNode;
|
|
38
|
+
/** A built-in accessory or any node (a `<Switch>`, a `<Badge>`, …). */
|
|
39
|
+
accessory?: ListItemAccessory | ReactNode;
|
|
40
|
+
/** Persistent blue highlight — the tapped-row state. */
|
|
41
|
+
selected?: boolean;
|
|
42
|
+
disabled?: boolean;
|
|
43
|
+
/** Renders the row as an `<a>`. */
|
|
44
|
+
href?: string;
|
|
45
|
+
/** With `onClick` (and no `href`) the row renders as a `<button>`. */
|
|
46
|
+
onClick?: MouseEventHandler<HTMLElement>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* One table cell: optional 29 × 29 icon (or glossy app-icon tile), bold title
|
|
50
|
+
* with subtitle, right-aligned detail text and an accessory. With `onClick` it
|
|
51
|
+
* is a `<button>`, with `href` an `<a>`, otherwise a plain `listitem`.
|
|
52
|
+
* Pressing (or `selected`) floods the cell with the blue gel and turns all
|
|
53
|
+
* text white — exactly like tapping a row on the 3GS.
|
|
54
|
+
*/
|
|
55
|
+
export declare const ListItem: import('react').ForwardRefExoticComponent<ListItemProps & import('react').RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { NavigationBarTint } from '../NavigationBar';
|
|
3
|
+
export interface ModalSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
|
|
4
|
+
open: boolean;
|
|
5
|
+
/** Called on Escape and by the default Cancel / Done bar buttons. */
|
|
6
|
+
onClose?: () => void;
|
|
7
|
+
/** NavigationBar title. A string also becomes the dialog's accessible name. */
|
|
8
|
+
title?: ReactNode;
|
|
9
|
+
/** NavigationBar left slot. Default: a `strings.cancel` ("Cancel") bar button that calls `onClose`; `null` hides it. */
|
|
10
|
+
left?: ReactNode;
|
|
11
|
+
/** NavigationBar right slot. Default: a blue `strings.done` ("Done") bar button that calls `onClose`; `null` hides it. */
|
|
12
|
+
right?: ReactNode;
|
|
13
|
+
/** Forwarded to the NavigationBar: `black` glass (default) or the blue-gray bar. */
|
|
14
|
+
tint?: NavigationBarTint;
|
|
15
|
+
/** Body background: the grouped-table pinstripe (default), plain black or the flat cell surface. */
|
|
16
|
+
background?: "pinstripe" | "black" | "surface";
|
|
17
|
+
/** `className` goes to the sheet panel; this one to the scrolling body. */
|
|
18
|
+
bodyClassName?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Default `false` → portal to `document.body` with a `position: fixed` backdrop.
|
|
21
|
+
* `true` → render in place with `position: absolute; inset: 0`, filling the
|
|
22
|
+
* nearest positioned ancestor (e.g. a phone screen in a showcase).
|
|
23
|
+
*/
|
|
24
|
+
contained?: boolean;
|
|
25
|
+
/** `aria-label` for the dialog when `title` isn't a plain string. Default `strings.dialog`. */
|
|
26
|
+
label?: string;
|
|
27
|
+
children: ReactNode;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The iOS 3 modally presented screen (`UIModalTransitionStyleCoverVertical`):
|
|
31
|
+
* a full-size panel that slides up from the bottom over the current screen,
|
|
32
|
+
* with its own navigation bar (Cancel / title / Done) and a scrolling body —
|
|
33
|
+
* Compose, Add Event, Settings forms. Renders nothing while `open` is false.
|
|
34
|
+
* The ref points at the sheet panel.
|
|
35
|
+
*/
|
|
36
|
+
export declare const ModalSheet: import('react').ForwardRefExoticComponent<ModalSheetProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ButtonHTMLAttributes, HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { LucideIcon } from 'lucide-react';
|
|
3
|
+
export type NavigationBarTint =
|
|
4
|
+
/** black glass — `UIBarStyleBlack` (default) */
|
|
5
|
+
"black"
|
|
6
|
+
/** the classic iOS 3 blue-gray bar */
|
|
7
|
+
| "blue";
|
|
8
|
+
export interface NavigationBarProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
|
|
9
|
+
/** Bold 20 px white title, centred over the full bar width; ellipsised when too long. */
|
|
10
|
+
title?: ReactNode;
|
|
11
|
+
/** Left slot — usually a `<BarButton variant="back">`. */
|
|
12
|
+
left?: ReactNode;
|
|
13
|
+
/** Right slot — usually a `<BarButton variant="done">` or a default bar button. */
|
|
14
|
+
right?: ReactNode;
|
|
15
|
+
/** `black` glass (default) or the classic blue-gray bar. */
|
|
16
|
+
tint?: NavigationBarTint;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The 44 px top bar: a vertical gradient with the hard highlight split at 50 %,
|
|
20
|
+
* a 1 px light rim on top and a 1 px black bottom edge. The title is centred
|
|
21
|
+
* over the whole width so it stays put regardless of how wide the buttons are.
|
|
22
|
+
*/
|
|
23
|
+
export declare const NavigationBar: import('react').ForwardRefExoticComponent<NavigationBarProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
24
|
+
export type BarButtonVariant =
|
|
25
|
+
/** dark gel — the everyday bar button */
|
|
26
|
+
"default"
|
|
27
|
+
/** the left-pointing arrow shape */
|
|
28
|
+
| "back"
|
|
29
|
+
/** blue gel — the primary action ("Done", "Save") */
|
|
30
|
+
| "done";
|
|
31
|
+
export interface BarButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
32
|
+
variant?: BarButtonVariant;
|
|
33
|
+
/** Any `lucide-react` icon, rendered flat in white before the label. */
|
|
34
|
+
icon?: LucideIcon;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The small 30 px gel button that lives in navigation bars and toolbars.
|
|
38
|
+
* `variant="back"` draws the pointed pill: two clipped layers (black
|
|
39
|
+
* silhouette + inset gel) stand in for the border that `clip-path` would cut off.
|
|
40
|
+
*/
|
|
41
|
+
export declare const BarButton: import('react').ForwardRefExoticComponent<BarButtonProps & import('react').RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export type NotificationBannerTint = "gray" | "blue" | "red" | "green";
|
|
3
|
+
export interface NotificationBannerProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
|
|
4
|
+
open: boolean;
|
|
5
|
+
/** Bold 14 px white line — the app or sender name. */
|
|
6
|
+
title: ReactNode;
|
|
7
|
+
/** 13 px line under the title; clamped to two lines with an ellipsis. */
|
|
8
|
+
message?: ReactNode;
|
|
9
|
+
/** Glyph for the 29 px app-icon tile, e.g. `<Icon icon={Mail} variant="flat" size={18} />`. */
|
|
10
|
+
icon?: ReactNode;
|
|
11
|
+
/** Tile gel colour. Default `gray`. */
|
|
12
|
+
iconTint?: NotificationBannerTint;
|
|
13
|
+
/** Small dark gel bar-button on the end side ("Reply"). */
|
|
14
|
+
actionLabel?: string;
|
|
15
|
+
/** Fires when the action button is tapped. */
|
|
16
|
+
onAction?: () => void;
|
|
17
|
+
/** Fires when the banner body (not the action) is tapped — e.g. open the app. */
|
|
18
|
+
onClick?: () => void;
|
|
19
|
+
/**
|
|
20
|
+
* Auto-dismiss: calls `onClose` after this many ms. Default 4000; `0` keeps
|
|
21
|
+
* the banner up until it is tapped, swiped or closed. The timer pauses while
|
|
22
|
+
* the banner is hovered, pressed or keyboard-focused and restarts when
|
|
23
|
+
* `open`, `duration` or `title` change (new content = new banner).
|
|
24
|
+
*/
|
|
25
|
+
duration?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Called after `duration`, after a swipe-up, after Escape, and after an
|
|
28
|
+
* action / body tap (see `dismissOnAction`). The caller sets `open` false.
|
|
29
|
+
*/
|
|
30
|
+
onClose?: () => void;
|
|
31
|
+
/** Whether an action / body tap also calls `onClose`. Default `true`. */
|
|
32
|
+
dismissOnAction?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Default `false` → portal to `document.body` with `position: fixed; top: 0`.
|
|
35
|
+
* `true` → render in place with `position: absolute; top: 0; inset-inline: 0`
|
|
36
|
+
* at the top of the nearest positioned ancestor (e.g. a phone screen in a showcase).
|
|
37
|
+
*/
|
|
38
|
+
contained?: boolean;
|
|
39
|
+
/** `aria-label` of the status region. Default "Notification". */
|
|
40
|
+
label?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The push-notification banner: a 60 px translucent black glass strip that
|
|
44
|
+
* drops over the status / nav bar with a glossy app-icon tile, a bold title,
|
|
45
|
+
* a short message, an optional action bar-button and a three-dot grip.
|
|
46
|
+
* Non-modal and auto-dismissing; tapping the body runs `onClick`, a swipe up
|
|
47
|
+
* slides it away. Renders nothing while `open` is false. The ref points at
|
|
48
|
+
* the banner.
|
|
49
|
+
*/
|
|
50
|
+
export declare const NotificationBanner: import('react').ForwardRefExoticComponent<NotificationBannerProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
export type PageControlSize =
|
|
3
|
+
/** 6 px dots — the home-screen pager (default) */
|
|
4
|
+
"sm"
|
|
5
|
+
/** 8 px dots — photo pagers, larger canvases */
|
|
6
|
+
| "md";
|
|
7
|
+
export interface PageControlProps extends Omit<HTMLAttributes<HTMLDivElement>, "onChange"> {
|
|
8
|
+
/** Number of pages. With `hideForSinglePage` (default) nothing renders when this is `<= 1`. */
|
|
9
|
+
count: number;
|
|
10
|
+
/** Controlled current page, 0-based. Clamped to `[0, count - 1]`. */
|
|
11
|
+
value?: number;
|
|
12
|
+
/** Uncontrolled initial page, 0-based. Default `0`. */
|
|
13
|
+
defaultValue?: number;
|
|
14
|
+
onChange?: (page: number) => void;
|
|
15
|
+
/** `aria-label` for the tablist. Default `strings.pages` ("Pages"). */
|
|
16
|
+
label?: string;
|
|
17
|
+
/** Render nothing for 0 or 1 pages (`UIPageControl.hidesForSinglePage`). Default `true`. */
|
|
18
|
+
hideForSinglePage?: boolean;
|
|
19
|
+
/** Dot size: `sm` = 6 px (default), `md` = 8 px. */
|
|
20
|
+
size?: PageControlSize;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The row of tiny dots under the home screen (`UIPageControl`): the current
|
|
24
|
+
* page is a solid white dot with a faint gloss, the others translucent white
|
|
25
|
+
* sunk into the surface with a dark rim.
|
|
26
|
+
*
|
|
27
|
+
* Interaction matches the original: tapping the strip's right half goes one
|
|
28
|
+
* page forward, the left half one back (no wrap); each dot is also a button
|
|
29
|
+
* that jumps straight to its page. Keyboard: Left/Right (and Home/End) move
|
|
30
|
+
* focus *and* select — roving tabindex, so the strip is a single Tab stop.
|
|
31
|
+
*/
|
|
32
|
+
export declare const PageControl: import('react').ForwardRefExoticComponent<PageControlProps & import('react').RefAttributes<HTMLDivElement>>;
|