@ponti-studios/ui 1.6.0 → 1.7.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/README.md +7 -11
- package/package.json +6 -31
- package/src/components/feedback/alert.tsx +8 -4
- package/src/components/feedback/index.ts +0 -4
- package/src/components/feedback/progress.stories.tsx +15 -0
- package/src/components/feedback/progress.tsx +14 -3
- package/src/components/feedback/update-guard.stories.tsx +4 -8
- package/src/components/feedback/update-guard.tsx +41 -272
- package/src/components/filters/filter-select.tsx +3 -5
- package/src/components/forms/date-picker.stories.tsx +158 -18
- package/src/components/forms/date-picker.tsx +286 -64
- package/src/components/forms/date-utils.ts +7 -2
- package/src/components/forms/drop-zone.tsx +11 -12
- package/src/components/forms/index.ts +2 -6
- package/src/components/forms/passkey-management.stories.tsx +8 -4
- package/src/components/forms/passkey-management.tsx +78 -42
- package/src/components/forms/radio-group.stories.tsx +3 -5
- package/src/components/forms/radio-group.tsx +2 -2
- package/src/components/forms/select.stories.tsx +16 -13
- package/src/components/forms/textarea.stories.tsx +1 -1
- package/src/components/layout/index.ts +2 -0
- package/src/components/layout/particle-background.stories.tsx +38 -0
- package/src/components/layout/particle-background.tsx +378 -0
- package/src/components/layout/scroll-area.stories.tsx +12 -4
- package/src/components/layout/scroll-area.tsx +41 -4
- package/src/components/navigation/tabs.stories.tsx +0 -21
- package/src/components/overlays/dialog.stories.tsx +38 -1
- package/src/components/overlays/dialog.tsx +53 -12
- package/src/components/overlays/index.ts +0 -11
- package/src/components/primitives/avatar-placeholder.svg +13 -0
- package/src/components/primitives/avatar.stories.tsx +2 -1
- package/src/components/primitives/badge.stories.tsx +13 -3
- package/src/components/primitives/badge.tsx +1 -1
- package/src/components/primitives/button.tsx +1 -1
- package/src/components/primitives/card.tsx +6 -2
- package/src/components/primitives/index.ts +0 -3
- package/src/index.ts +1 -3
- package/src/lib/index.ts +2 -3
- package/src/styles/animations.css +62 -0
- package/src/styles/index.css +27 -0
- package/src/styles/tokens/generated/dark.colors.generated.ts +15 -12
- package/src/styles/tokens/generated/dark.css +15 -12
- package/src/styles/tokens/generated/light.colors.generated.ts +14 -11
- package/src/styles/tokens/generated/light.css +14 -11
- package/src/styles/tokens/index.ts +0 -3
- package/src/styles/tokens/source/dark.tokens.json +24 -12
- package/src/styles/tokens/source/light.tokens.json +23 -11
- package/src/styles/tokens/typography.stories.tsx +157 -0
- package/src/components/feedback/file-upload-status.stories.tsx +0 -57
- package/src/components/feedback/file-upload-status.tsx +0 -160
- package/src/components/feedback/progress-bar.stories.tsx +0 -39
- package/src/components/feedback/progress-bar.tsx +0 -22
- package/src/components/forms/calendar.stories.tsx +0 -30
- package/src/components/forms/calendar.tsx +0 -75
- package/src/components/forms/date-field.stories.tsx +0 -202
- package/src/components/forms/date-field.tsx +0 -179
- package/src/components/overlays/alert-dialog.stories.tsx +0 -45
- package/src/components/overlays/alert-dialog.tsx +0 -116
- package/src/components/primitives/label.stories.tsx +0 -29
- package/src/components/primitives/label.tsx +0 -20
- package/src/components/primitives/status-badge.stories.tsx +0 -52
- package/src/components/primitives/status-badge.tsx +0 -33
- package/src/lib/create-memory-storage.ts +0 -24
- package/src/native/card.tsx +0 -36
- package/src/native/icon-button.tsx +0 -41
- package/src/native/index.ts +0 -38
- package/src/native/list-row.tsx +0 -67
- package/src/native/make-styles.ts +0 -32
- package/src/native/shadows.ts +0 -38
- package/src/native/text-field.tsx +0 -34
- package/src/native/uniwind.d.ts +0 -1
- package/src/native/use-theme-colors.ts +0 -19
- package/src/styles/tokens/foundations.stories.tsx +0 -109
- package/src/styles/tokens/generated/native.generated.ts +0 -266
- package/src/styles/tokens/normalize-native.ts +0 -88
- package/src/styles/tokens/source/native.tokens.json +0 -204
- package/src/styles/tokens/style-dictionary.native.mjs +0 -26
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export function createMemoryStorage(): Storage {
|
|
2
|
-
const store = new Map<string, string>();
|
|
3
|
-
|
|
4
|
-
return {
|
|
5
|
-
get length() {
|
|
6
|
-
return store.size;
|
|
7
|
-
},
|
|
8
|
-
clear() {
|
|
9
|
-
store.clear();
|
|
10
|
-
},
|
|
11
|
-
getItem(key) {
|
|
12
|
-
return store.get(key) ?? null;
|
|
13
|
-
},
|
|
14
|
-
key(index) {
|
|
15
|
-
return Array.from(store.keys())[index] ?? null;
|
|
16
|
-
},
|
|
17
|
-
removeItem(key) {
|
|
18
|
-
store.delete(key);
|
|
19
|
-
},
|
|
20
|
-
setItem(key, value) {
|
|
21
|
-
store.set(key, value);
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
}
|
package/src/native/card.tsx
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { Text, View, type TextProps, type ViewProps } from "react-native";
|
|
3
|
-
|
|
4
|
-
import { cn } from "../lib/utils";
|
|
5
|
-
|
|
6
|
-
function Card({ className, ...props }: ViewProps) {
|
|
7
|
-
return (
|
|
8
|
-
<View className={cn("bg-card gap-4 rounded border border-border p-4", className)} {...props} />
|
|
9
|
-
);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function CardHeader({ className, ...props }: ViewProps) {
|
|
13
|
-
return <View className={cn("gap-1", className)} {...props} />;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function CardTitle({ className, ...props }: TextProps) {
|
|
17
|
-
return <Text className={cn("text-card-foreground text-xl", className)} {...props} />;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function CardDescription({ className, ...props }: TextProps) {
|
|
21
|
-
return <Text className={cn("text-muted-foreground text-xs", className)} {...props} />;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function CardAction({ className, ...props }: ViewProps) {
|
|
25
|
-
return <View className={cn("self-start", className)} {...props} />;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function CardContent({ className, ...props }: ViewProps) {
|
|
29
|
-
return <View className={className} {...props} />;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function CardFooter({ className, ...props }: ViewProps) {
|
|
33
|
-
return <View className={cn("flex-row items-center", className)} {...props} />;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle };
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
2
|
-
import { Pressable } from "react-native";
|
|
3
|
-
import { useCSSVariable } from "uniwind";
|
|
4
|
-
|
|
5
|
-
interface IconButtonProps {
|
|
6
|
-
accessibilityLabel?: string;
|
|
7
|
-
children: ReactNode;
|
|
8
|
-
disabled?: boolean;
|
|
9
|
-
onPress?: () => void;
|
|
10
|
-
testID?: string;
|
|
11
|
-
variant?: "bordered" | "plain";
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function IconButton({
|
|
15
|
-
accessibilityLabel,
|
|
16
|
-
children,
|
|
17
|
-
disabled = false,
|
|
18
|
-
onPress,
|
|
19
|
-
testID,
|
|
20
|
-
variant = "bordered",
|
|
21
|
-
}: IconButtonProps) {
|
|
22
|
-
const [border] = useCSSVariable(["--color-border"]) as string[];
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<Pressable
|
|
26
|
-
accessibilityLabel={accessibilityLabel}
|
|
27
|
-
accessibilityRole="button"
|
|
28
|
-
disabled={disabled}
|
|
29
|
-
onPress={onPress}
|
|
30
|
-
testID={testID}
|
|
31
|
-
className={`w-8 h-8 rounded-full border items-center justify-center ${variant === "plain" ? "border-0" : ""}`}
|
|
32
|
-
style={({ pressed }) => [
|
|
33
|
-
{ borderColor: variant === "plain" ? "transparent" : border },
|
|
34
|
-
pressed && { opacity: 0.7 },
|
|
35
|
-
disabled && { opacity: 0.4 },
|
|
36
|
-
]}
|
|
37
|
-
>
|
|
38
|
-
{children}
|
|
39
|
-
</Pressable>
|
|
40
|
-
);
|
|
41
|
-
}
|
package/src/native/index.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* React Native entry point.
|
|
3
|
-
*
|
|
4
|
-
* Kept as its own subpath (`@ponti-studios/ui/native`) because it is the only
|
|
5
|
-
* part of the package that imports `react-native`. Nothing here may import web
|
|
6
|
-
* code, so web consumers never pull React Native into their graph and native
|
|
7
|
-
* consumers never pull in react-dom.
|
|
8
|
-
*/
|
|
9
|
-
export {
|
|
10
|
-
Card,
|
|
11
|
-
CardAction,
|
|
12
|
-
CardContent,
|
|
13
|
-
CardDescription,
|
|
14
|
-
CardFooter,
|
|
15
|
-
CardHeader,
|
|
16
|
-
CardTitle,
|
|
17
|
-
} from "./card";
|
|
18
|
-
export { IconButton } from "./icon-button";
|
|
19
|
-
export { ListRow } from "./list-row";
|
|
20
|
-
export { createMakeStyles, type NamedStyles } from "./make-styles";
|
|
21
|
-
export { nativeShadows, type NativeShadowLayer } from "./shadows";
|
|
22
|
-
export { TextField } from "./text-field";
|
|
23
|
-
export { useColorMode, useThemeColors } from "./use-theme-colors";
|
|
24
|
-
|
|
25
|
-
export {
|
|
26
|
-
borderRadius as nativeBorderRadius,
|
|
27
|
-
componentSize as nativeComponentSize,
|
|
28
|
-
fontFamily as nativeFontFamily,
|
|
29
|
-
screenMargin as nativeScreenMargin,
|
|
30
|
-
spacing as nativeSpacing,
|
|
31
|
-
streamItem as nativeStreamItem,
|
|
32
|
-
typography as nativeTypography,
|
|
33
|
-
type BorderRadiusToken,
|
|
34
|
-
type ComponentSizeToken,
|
|
35
|
-
type SpacingToken,
|
|
36
|
-
type TypographyVariant,
|
|
37
|
-
} from "../styles/tokens/normalize-native";
|
|
38
|
-
export { motion as nativeMotion } from "../styles/tokens";
|
package/src/native/list-row.tsx
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
2
|
-
import { Pressable, type StyleProp, Text, type TextStyle, View } from "react-native";
|
|
3
|
-
import { useCSSVariable } from "uniwind";
|
|
4
|
-
|
|
5
|
-
interface ListRowProps {
|
|
6
|
-
accessibilityLabel: string;
|
|
7
|
-
actionTestID?: string;
|
|
8
|
-
eyebrow?: string;
|
|
9
|
-
leading?: ReactNode;
|
|
10
|
-
onLongPress?: () => void;
|
|
11
|
-
onPress: () => void;
|
|
12
|
-
subtitle?: string | null;
|
|
13
|
-
testID?: string;
|
|
14
|
-
title: string;
|
|
15
|
-
titleStyle?: StyleProp<TextStyle>;
|
|
16
|
-
trailing?: ReactNode;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function ListRow({
|
|
20
|
-
accessibilityLabel,
|
|
21
|
-
actionTestID,
|
|
22
|
-
eyebrow,
|
|
23
|
-
leading,
|
|
24
|
-
onLongPress,
|
|
25
|
-
onPress,
|
|
26
|
-
subtitle,
|
|
27
|
-
testID,
|
|
28
|
-
title,
|
|
29
|
-
titleStyle,
|
|
30
|
-
trailing,
|
|
31
|
-
}: ListRowProps) {
|
|
32
|
-
const [muted] = useCSSVariable(["--color-muted"]) as string[];
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<Pressable
|
|
36
|
-
accessibilityLabel={accessibilityLabel}
|
|
37
|
-
accessibilityRole="button"
|
|
38
|
-
onLongPress={onLongPress}
|
|
39
|
-
onPress={onPress}
|
|
40
|
-
className="flex-row items-center gap-3 min-h-14 border-b border-border px-4 py-2"
|
|
41
|
-
style={({ pressed }) => pressed && { backgroundColor: muted }}
|
|
42
|
-
testID={testID ?? actionTestID}
|
|
43
|
-
>
|
|
44
|
-
{leading ? <View className="items-center justify-center w-6">{leading}</View> : null}
|
|
45
|
-
<View className="flex-1 gap-0.5 min-w-0">
|
|
46
|
-
{eyebrow ? (
|
|
47
|
-
<Text className="text-caption2 text-muted-foreground tracking-[0.2]">{eyebrow}</Text>
|
|
48
|
-
) : null}
|
|
49
|
-
<Text numberOfLines={2} className="text-body text-foreground" style={titleStyle}>
|
|
50
|
-
{title}
|
|
51
|
-
</Text>
|
|
52
|
-
{subtitle ? (
|
|
53
|
-
<Text
|
|
54
|
-
ellipsizeMode="tail"
|
|
55
|
-
numberOfLines={1}
|
|
56
|
-
className="text-caption1 text-muted-foreground"
|
|
57
|
-
>
|
|
58
|
-
{subtitle}
|
|
59
|
-
</Text>
|
|
60
|
-
) : null}
|
|
61
|
-
</View>
|
|
62
|
-
{trailing ? <View className="items-center justify-center">{trailing}</View> : null}
|
|
63
|
-
</Pressable>
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export { ListRow };
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { ImageStyle, TextStyle, ViewStyle } from "react-native";
|
|
2
|
-
|
|
3
|
-
export type NamedStyles = Record<string, ViewStyle | TextStyle | ImageStyle>;
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Builds a `makeStyles` helper bound to a consuming app's own theme hook.
|
|
7
|
-
*
|
|
8
|
-
* The theme *shape* stays owned by the app — this package supplies only the
|
|
9
|
-
* mechanism — so `Theme` is a type parameter rather than a type exported from
|
|
10
|
-
* here. An app calls this once with its `useTheme` and uses the result
|
|
11
|
-
* everywhere:
|
|
12
|
-
*
|
|
13
|
-
* ```ts
|
|
14
|
-
* export const makeStyles = createMakeStyles(useTheme);
|
|
15
|
-
*
|
|
16
|
-
* const useStyles = makeStyles((theme) => ({
|
|
17
|
-
* card: { backgroundColor: theme.colors.card },
|
|
18
|
-
* }));
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* The returned `useStyles` is a hook: it calls `useTheme` on every render, so
|
|
22
|
-
* styles re-resolve when the color mode changes. Styles are returned as plain
|
|
23
|
-
* objects rather than passed through `StyleSheet.create`, since they are
|
|
24
|
-
* rebuilt per render and React Native accepts plain style objects directly.
|
|
25
|
-
*/
|
|
26
|
-
export function createMakeStyles<Theme>(useTheme: () => Theme) {
|
|
27
|
-
return function makeStyles<T extends NamedStyles>(factory: (theme: Theme) => T & NamedStyles) {
|
|
28
|
-
return function useStyles(): T {
|
|
29
|
-
return factory(useTheme());
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
}
|
package/src/native/shadows.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { shadows, type ShadowToken } from "../styles/tokens/index";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* One layer of a shadow in the shape React Native's `boxShadow` expects.
|
|
5
|
-
*
|
|
6
|
-
* The shared shadow tokens are authored for CSS, where each dimension carries
|
|
7
|
-
* its own unit. React Native takes bare numbers (density-independent pixels),
|
|
8
|
-
* so the unit is dropped here rather than at every call site.
|
|
9
|
-
*/
|
|
10
|
-
export interface NativeShadowLayer {
|
|
11
|
-
color: string;
|
|
12
|
-
offsetX: number;
|
|
13
|
-
offsetY: number;
|
|
14
|
-
blurRadius: number;
|
|
15
|
-
spreadDistance: number;
|
|
16
|
-
inset: boolean;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* The shared shadow scale translated to React Native's `boxShadow` shape.
|
|
21
|
-
*
|
|
22
|
-
* Every token maps to an array of layers, including `none`, which is a single
|
|
23
|
-
* fully transparent layer rather than an empty array — that keeps the value
|
|
24
|
-
* assignable wherever a real shadow is expected.
|
|
25
|
-
*/
|
|
26
|
-
export const nativeShadows = Object.fromEntries(
|
|
27
|
-
Object.entries(shadows).map(([name, layers]) => [
|
|
28
|
-
name,
|
|
29
|
-
layers.map((layer) => ({
|
|
30
|
-
color: layer.color,
|
|
31
|
-
offsetX: layer.offsetX.value,
|
|
32
|
-
offsetY: layer.offsetY.value,
|
|
33
|
-
blurRadius: layer.blur.value,
|
|
34
|
-
spreadDistance: layer.spread.value,
|
|
35
|
-
inset: false,
|
|
36
|
-
})),
|
|
37
|
-
]),
|
|
38
|
-
) as Record<ShadowToken, NativeShadowLayer[]>;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { forwardRef, useState } from "react";
|
|
2
|
-
import { TextInput, type TextInputProps } from "react-native";
|
|
3
|
-
import { useCSSVariable } from "uniwind";
|
|
4
|
-
|
|
5
|
-
export const TextField = forwardRef<TextInput, TextInputProps>(function TextField(
|
|
6
|
-
{ onBlur, onFocus, style, ...props },
|
|
7
|
-
ref,
|
|
8
|
-
) {
|
|
9
|
-
const [ring, borderInput, foreground, mutedForeground] = useCSSVariable([
|
|
10
|
-
"--color-ring",
|
|
11
|
-
"--color-input",
|
|
12
|
-
"--color-foreground",
|
|
13
|
-
"--color-muted-foreground",
|
|
14
|
-
]) as string[];
|
|
15
|
-
const [focused, setFocused] = useState(false);
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<TextInput
|
|
19
|
-
{...props}
|
|
20
|
-
ref={ref}
|
|
21
|
-
onBlur={(event) => {
|
|
22
|
-
setFocused(false);
|
|
23
|
-
onBlur?.(event);
|
|
24
|
-
}}
|
|
25
|
-
onFocus={(event) => {
|
|
26
|
-
setFocused(true);
|
|
27
|
-
onFocus?.(event);
|
|
28
|
-
}}
|
|
29
|
-
placeholderTextColor={props.placeholderTextColor ?? mutedForeground}
|
|
30
|
-
className="rounded-md border min-h-11 px-4 py-3 text-base"
|
|
31
|
-
style={[{ borderColor: focused ? ring : borderInput, color: foreground }, style]}
|
|
32
|
-
/>
|
|
33
|
-
);
|
|
34
|
-
});
|
package/src/native/uniwind.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/// <reference types="uniwind/types" />
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { useColorScheme } from "react-native";
|
|
2
|
-
|
|
3
|
-
import { colorThemes, type ColorMode, type ColorTheme } from "../styles/tokens/index";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Resolves the active color mode from the OS appearance setting.
|
|
7
|
-
*
|
|
8
|
-
* React Native's `useColorScheme` reports `null` before the appearance module
|
|
9
|
-
* has settled, so anything that isn't explicitly "dark" resolves to light —
|
|
10
|
-
* callers always receive a concrete mode rather than having to handle null.
|
|
11
|
-
*/
|
|
12
|
-
export function useColorMode(): ColorMode {
|
|
13
|
-
return useColorScheme() === "dark" ? "dark" : "light";
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** The full color token set for the active OS appearance. */
|
|
17
|
-
export function useThemeColors(): ColorTheme {
|
|
18
|
-
return colorThemes[useColorMode()];
|
|
19
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
|
|
3
|
-
const meta: Meta = { title: "Foundations/Tailwind Defaults", parameters: { layout: "fullscreen" } };
|
|
4
|
-
export default meta;
|
|
5
|
-
type Story = StoryObj<typeof meta>;
|
|
6
|
-
|
|
7
|
-
export const SpacingAndType: Story = {
|
|
8
|
-
render: () => (
|
|
9
|
-
<main className="bg-background text-foreground grid min-h-screen gap-10 p-6 md:p-10">
|
|
10
|
-
<section className="grid gap-6">
|
|
11
|
-
<header className="grid gap-2">
|
|
12
|
-
<p className="text-muted-foreground text-sm">Foundations / rhythm</p>
|
|
13
|
-
<h1 className="text-4xl font-semibold tracking-tight">Tailwind defaults, directly.</h1>
|
|
14
|
-
<p className="text-muted-foreground max-w-2xl text-base">
|
|
15
|
-
The specimen uses the shared Tailwind spacing and type scales.
|
|
16
|
-
</p>
|
|
17
|
-
</header>
|
|
18
|
-
<div className="grid gap-2">
|
|
19
|
-
{[1, 2, 3, 4, 6, 8, 12, 16].map((size) => (
|
|
20
|
-
<div key={size} className="flex items-center gap-3">
|
|
21
|
-
<span className="text-muted-foreground w-12 font-mono text-xs tabular-nums">
|
|
22
|
-
{size}
|
|
23
|
-
</span>
|
|
24
|
-
<div
|
|
25
|
-
className="bg-accent h-3 rounded-sm"
|
|
26
|
-
style={{ width: `calc(var(--spacing) * ${size})` }}
|
|
27
|
-
aria-hidden="true"
|
|
28
|
-
/>
|
|
29
|
-
</div>
|
|
30
|
-
))}
|
|
31
|
-
</div>
|
|
32
|
-
</section>
|
|
33
|
-
<section className="border-border bg-card grid gap-5 rounded-xl border p-6">
|
|
34
|
-
<h2 className="text-2xl font-semibold">Typography scale</h2>
|
|
35
|
-
<div className="grid gap-4">
|
|
36
|
-
{(
|
|
37
|
-
[
|
|
38
|
-
"text-xs",
|
|
39
|
-
"text-sm",
|
|
40
|
-
"text-base",
|
|
41
|
-
"text-lg",
|
|
42
|
-
"text-xl",
|
|
43
|
-
"text-2xl",
|
|
44
|
-
"text-4xl",
|
|
45
|
-
] as const
|
|
46
|
-
).map((size) => (
|
|
47
|
-
<p key={size} className={`${size} text-foreground`}>
|
|
48
|
-
{size}
|
|
49
|
-
</p>
|
|
50
|
-
))}
|
|
51
|
-
</div>
|
|
52
|
-
</section>
|
|
53
|
-
</main>
|
|
54
|
-
),
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export const Surfaces: Story = {
|
|
58
|
-
render: () => (
|
|
59
|
-
<main className="bg-background text-foreground grid min-h-screen gap-6 p-6 md:p-10">
|
|
60
|
-
<header className="grid gap-2">
|
|
61
|
-
<p className="text-muted-foreground text-sm">Foundations / surfaces</p>
|
|
62
|
-
<h1 className="text-4xl font-semibold tracking-tight">Standard semantic layers.</h1>
|
|
63
|
-
</header>
|
|
64
|
-
<div className="grid gap-4 md:grid-cols-2">
|
|
65
|
-
{[
|
|
66
|
-
["Background", "bg-background"],
|
|
67
|
-
["Card", "bg-card"],
|
|
68
|
-
["Popover", "bg-popover"],
|
|
69
|
-
["Muted", "bg-muted"],
|
|
70
|
-
].map(([name, className]) => (
|
|
71
|
-
<div
|
|
72
|
-
key={name}
|
|
73
|
-
className={`${className} border-border grid min-h-40 content-start gap-2 rounded-xl border p-5`}
|
|
74
|
-
>
|
|
75
|
-
<h2 className="text-lg font-semibold">{name}</h2>
|
|
76
|
-
<p className="text-muted-foreground text-sm">{className}</p>
|
|
77
|
-
</div>
|
|
78
|
-
))}
|
|
79
|
-
</div>
|
|
80
|
-
</main>
|
|
81
|
-
),
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
export const Motion: Story = {
|
|
85
|
-
render: () => (
|
|
86
|
-
<main className="bg-background text-foreground grid min-h-screen gap-8 p-6 md:p-10">
|
|
87
|
-
<header className="grid gap-2">
|
|
88
|
-
<p className="text-muted-foreground text-sm">Foundations / motion</p>
|
|
89
|
-
<h1 className="text-4xl font-semibold tracking-tight">
|
|
90
|
-
Motion stays standard and reducible.
|
|
91
|
-
</h1>
|
|
92
|
-
</header>
|
|
93
|
-
<div className="grid gap-4 sm:grid-cols-3">
|
|
94
|
-
<div className="motion-safe:animate-in motion-safe:fade-in-0 border-border bg-card grid min-h-32 place-content-center gap-2 rounded-xl border p-5 motion-reduce:animate-none">
|
|
95
|
-
<span className="text-lg font-semibold">Enter</span>
|
|
96
|
-
<span className="text-muted-foreground text-sm">150ms</span>
|
|
97
|
-
</div>
|
|
98
|
-
<button className="border-border bg-card hover:bg-accent focus-visible:ring-ring grid min-h-32 place-content-center gap-2 rounded-xl border p-5 text-left transition-colors focus-visible:ring-2 focus-visible:outline-none motion-reduce:transition-none">
|
|
99
|
-
<span className="text-lg font-semibold">Press</span>
|
|
100
|
-
<span className="text-muted-foreground text-sm">System focus</span>
|
|
101
|
-
</button>
|
|
102
|
-
<div className="border-border bg-card grid min-h-32 place-content-center gap-2 rounded-xl border p-5 motion-safe:animate-pulse motion-reduce:animate-none">
|
|
103
|
-
<span className="text-lg font-semibold">Loading</span>
|
|
104
|
-
<span className="text-muted-foreground text-sm">Stable geometry</span>
|
|
105
|
-
</div>
|
|
106
|
-
</div>
|
|
107
|
-
</main>
|
|
108
|
-
),
|
|
109
|
-
};
|