@ponti-studios/ui 1.0.0 → 1.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/package.json +7 -2
- package/src/components/data-display/sort-controls.tsx +8 -11
- package/src/components/data-display/sort-row.tsx +49 -35
- package/src/components/navigation/pagination-controls.tsx +1 -1
- package/src/components/overlays/sheet.tsx +22 -7
- package/src/native/card.tsx +34 -0
- package/src/native/icon-button.tsx +41 -0
- package/src/native/index.ts +17 -0
- package/src/native/text-field.tsx +34 -0
- package/src/native/uniwind.d.ts +1 -0
- package/src/styles/animations.css +91 -0
- package/src/styles/index.css +5 -3
- package/src/styles/tokens/generated/foundations.css +1 -0
- package/src/styles/tokens/generated/foundations.generated.ts +1 -0
- package/src/styles/tokens/generated/native.generated.ts +238 -0
- package/src/styles/tokens/normalize-native.ts +86 -0
- package/src/styles/tokens/source/foundations.tokens.json +2 -1
- package/src/styles/tokens/source/native.tokens.json +169 -0
- package/src/styles/tokens/style-dictionary.native.mjs +23 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ponti-studios/ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared UI component library for Ponti Studios",
|
|
6
6
|
"license": "MIT",
|
|
@@ -133,13 +133,15 @@
|
|
|
133
133
|
"style-dictionary": "5.5.0",
|
|
134
134
|
"tailwindcss": "^4.3.3",
|
|
135
135
|
"typescript": "6.0.3",
|
|
136
|
+
"uniwind": "^1.10.1",
|
|
136
137
|
"vite": "^8.1.5",
|
|
137
138
|
"vitest": "^4.1.10"
|
|
138
139
|
},
|
|
139
140
|
"peerDependencies": {
|
|
140
141
|
"react": "^18.2.0 || ^19.0.0",
|
|
141
142
|
"react-dom": "^18.2.0 || ^19.0.0",
|
|
142
|
-
"react-native": ">=0.74"
|
|
143
|
+
"react-native": ">=0.74",
|
|
144
|
+
"uniwind": ">=1.10.0"
|
|
143
145
|
},
|
|
144
146
|
"peerDependenciesMeta": {
|
|
145
147
|
"react-dom": {
|
|
@@ -147,6 +149,9 @@
|
|
|
147
149
|
},
|
|
148
150
|
"react-native": {
|
|
149
151
|
"optional": true
|
|
152
|
+
},
|
|
153
|
+
"uniwind": {
|
|
154
|
+
"optional": true
|
|
150
155
|
}
|
|
151
156
|
},
|
|
152
157
|
"packageManager": "pnpm@11.10.0"
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
DropdownMenu,
|
|
6
6
|
DropdownMenuContent,
|
|
7
7
|
DropdownMenuGroup,
|
|
8
|
-
DropdownMenuItem,
|
|
9
8
|
DropdownMenuLabel,
|
|
10
9
|
DropdownMenuSeparator,
|
|
11
10
|
DropdownMenuTrigger,
|
|
@@ -57,10 +56,9 @@ export function SortControls({
|
|
|
57
56
|
.filter((_, i) => i !== index)
|
|
58
57
|
.map((option) => option.field);
|
|
59
58
|
return (
|
|
60
|
-
<
|
|
59
|
+
<div
|
|
61
60
|
key={sort.field}
|
|
62
|
-
|
|
63
|
-
className={`p-0 focus:bg-transparent ${index === focusedSortIndex ? "bg-muted" : ""}`}
|
|
61
|
+
className={`rounded-sm ${index === focusedSortIndex ? "bg-muted" : ""}`}
|
|
64
62
|
>
|
|
65
63
|
<SortRow
|
|
66
64
|
sortOption={sort}
|
|
@@ -70,27 +68,26 @@ export function SortControls({
|
|
|
70
68
|
updateSortOption={updateSortOption}
|
|
71
69
|
removeSortOption={removeSortOption}
|
|
72
70
|
/>
|
|
73
|
-
</
|
|
71
|
+
</div>
|
|
74
72
|
);
|
|
75
73
|
})}
|
|
76
74
|
</DropdownMenuGroup>
|
|
77
75
|
{availableFieldsToAdd.length > 0 && (
|
|
78
76
|
<>
|
|
79
77
|
<DropdownMenuSeparator />
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
<button
|
|
79
|
+
type="button"
|
|
80
|
+
onClick={() => {
|
|
83
81
|
const firstAvailable = availableFieldsToAdd[0];
|
|
84
82
|
if (firstAvailable) {
|
|
85
83
|
addSortOption({ field: firstAvailable, direction: "desc" });
|
|
86
84
|
}
|
|
87
85
|
}}
|
|
88
|
-
|
|
89
|
-
className="mt-1"
|
|
86
|
+
className="hover:bg-muted focus-visible:ring-ring mt-1 flex w-full cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none focus-visible:ring-2 focus-visible:ring-offset-2"
|
|
90
87
|
>
|
|
91
88
|
<PlusCircle className="mr-2 size-4" />
|
|
92
89
|
Add Sort Criterion
|
|
93
|
-
</
|
|
90
|
+
</button>
|
|
94
91
|
</>
|
|
95
92
|
)}
|
|
96
93
|
</DropdownMenuContent>
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
import { ArrowDownWideNarrow, ArrowUpWideNarrow, X } from "lucide-react";
|
|
2
|
+
|
|
1
3
|
import type { SortField, SortOption } from "../../hooks/sort.types";
|
|
2
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
DropdownMenu,
|
|
6
|
+
DropdownMenuContent,
|
|
7
|
+
DropdownMenuItem,
|
|
8
|
+
DropdownMenuTrigger,
|
|
9
|
+
} from "../overlays/dropdown-menu";
|
|
3
10
|
import { Button } from "../primitives/button";
|
|
4
|
-
import { X } from "lucide-react";
|
|
5
11
|
|
|
6
12
|
export interface SortRowProps {
|
|
7
13
|
sortOption: SortOption;
|
|
@@ -12,6 +18,10 @@ export interface SortRowProps {
|
|
|
12
18
|
removeSortOption: (index: number) => void;
|
|
13
19
|
}
|
|
14
20
|
|
|
21
|
+
function fieldLabel(field: SortField) {
|
|
22
|
+
return field.charAt(0).toUpperCase() + field.slice(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
15
25
|
export function SortRow({
|
|
16
26
|
sortOption,
|
|
17
27
|
index,
|
|
@@ -25,47 +35,51 @@ export function SortRow({
|
|
|
25
35
|
);
|
|
26
36
|
|
|
27
37
|
return (
|
|
28
|
-
<div
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
<div className="flex w-full items-center gap-1">
|
|
39
|
+
<DropdownMenu>
|
|
40
|
+
<DropdownMenuTrigger asChild>
|
|
41
|
+
<button
|
|
42
|
+
type="button"
|
|
43
|
+
className="hover:bg-muted focus-visible:ring-ring flex-1 rounded-md px-2 py-1.5 text-left text-sm outline-none focus-visible:ring-2 focus-visible:ring-offset-2"
|
|
44
|
+
>
|
|
45
|
+
{fieldLabel(sortOption.field)}
|
|
46
|
+
</button>
|
|
47
|
+
</DropdownMenuTrigger>
|
|
48
|
+
<DropdownMenuContent>
|
|
37
49
|
{availableFieldsForCurrentSelect.map((field) => (
|
|
38
|
-
<
|
|
39
|
-
{field
|
|
40
|
-
|
|
50
|
+
<DropdownMenuItem
|
|
51
|
+
key={field}
|
|
52
|
+
onClick={() => updateSortOption(index, { ...sortOption, field })}
|
|
53
|
+
>
|
|
54
|
+
{fieldLabel(field)}
|
|
55
|
+
</DropdownMenuItem>
|
|
41
56
|
))}
|
|
42
|
-
</
|
|
43
|
-
</
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
57
|
+
</DropdownMenuContent>
|
|
58
|
+
</DropdownMenu>
|
|
59
|
+
<Button
|
|
60
|
+
variant="ghost"
|
|
61
|
+
size="sm"
|
|
62
|
+
className="size-8 p-0"
|
|
63
|
+
aria-label={sortOption.direction === "asc" ? "Sorted ascending" : "Sorted descending"}
|
|
64
|
+
onClick={() =>
|
|
65
|
+
updateSortOption(index, {
|
|
66
|
+
...sortOption,
|
|
67
|
+
direction: sortOption.direction === "asc" ? "desc" : "asc",
|
|
68
|
+
})
|
|
69
|
+
}
|
|
51
70
|
>
|
|
52
|
-
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
</SelectItem>
|
|
59
|
-
<SelectItem value="desc" className="text-xs">
|
|
60
|
-
Descending
|
|
61
|
-
</SelectItem>
|
|
62
|
-
</SelectContent>
|
|
63
|
-
</Select>
|
|
71
|
+
{sortOption.direction === "asc" ? (
|
|
72
|
+
<ArrowUpWideNarrow className="size-4" />
|
|
73
|
+
) : (
|
|
74
|
+
<ArrowDownWideNarrow className="size-4" />
|
|
75
|
+
)}
|
|
76
|
+
</Button>
|
|
64
77
|
<Button
|
|
65
78
|
variant="ghost"
|
|
66
79
|
size="sm"
|
|
67
80
|
onClick={() => removeSortOption(index)}
|
|
68
81
|
className="size-8 p-0"
|
|
82
|
+
aria-label="Remove sort criterion"
|
|
69
83
|
>
|
|
70
84
|
<X className="text-muted-foreground size-4" />
|
|
71
85
|
</Button>
|
|
@@ -15,7 +15,7 @@ export function PaginationControls({
|
|
|
15
15
|
onPageChange,
|
|
16
16
|
}: PaginationControlsProps) {
|
|
17
17
|
return (
|
|
18
|
-
<div className="border-border bg-background text-foreground inline-flex items-center overflow-hidden rounded-full border text-sm">
|
|
18
|
+
<div className="border-border bg-background text-foreground inline-flex w-fit shrink-0 items-center self-start overflow-hidden rounded-full border text-sm">
|
|
19
19
|
<Button
|
|
20
20
|
type="button"
|
|
21
21
|
variant="outline"
|
|
@@ -49,18 +49,28 @@ const SheetOverlay = React.forwardRef<
|
|
|
49
49
|
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Backdrop>
|
|
50
50
|
>(({ className, ...props }, ref) => (
|
|
51
51
|
<SheetPrimitive.Backdrop
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
className,
|
|
55
|
-
)}
|
|
52
|
+
data-slot="sheet-overlay"
|
|
53
|
+
className={cn("fixed inset-0 z-50 bg-black/80", className)}
|
|
56
54
|
{...props}
|
|
57
55
|
ref={ref}
|
|
58
56
|
/>
|
|
59
57
|
));
|
|
60
58
|
SheetOverlay.displayName = "SheetOverlay";
|
|
61
59
|
|
|
62
|
-
const sheetClassName =
|
|
63
|
-
|
|
60
|
+
const sheetClassName = [
|
|
61
|
+
// Appearance
|
|
62
|
+
"bg-background text-foreground rounded-xl border shadow-lg",
|
|
63
|
+
// Layout
|
|
64
|
+
"flex flex-col gap-6 p-4",
|
|
65
|
+
// Position: floats off every edge, anchored to the bottom on mobile
|
|
66
|
+
"fixed z-50 inset-x-2 bottom-[max(0.5rem,env(safe-area-inset-bottom))]",
|
|
67
|
+
// Size: mobile
|
|
68
|
+
"max-h-[calc(100dvh-2rem)] min-h-[30dvh]",
|
|
69
|
+
// Position: anchored to the right edge on desktop
|
|
70
|
+
"md:inset-y-2 md:right-2 md:left-auto md:bottom-auto",
|
|
71
|
+
// Size: desktop
|
|
72
|
+
"md:w-3/4 md:max-w-sm md:min-h-0",
|
|
73
|
+
];
|
|
64
74
|
|
|
65
75
|
interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Popup> {}
|
|
66
76
|
|
|
@@ -70,7 +80,12 @@ const SheetContent = React.forwardRef<
|
|
|
70
80
|
>(({ className, children, ...props }, ref) => (
|
|
71
81
|
<SheetPortal>
|
|
72
82
|
<SheetOverlay />
|
|
73
|
-
<SheetPrimitive.Popup
|
|
83
|
+
<SheetPrimitive.Popup
|
|
84
|
+
ref={ref}
|
|
85
|
+
data-slot="sheet-content"
|
|
86
|
+
className={cn(sheetClassName, className)}
|
|
87
|
+
{...props}
|
|
88
|
+
>
|
|
74
89
|
<SheetPrimitive.Close className="text-muted-foreground hover:bg-muted hover:text-muted-foreground focus-visible:outline-ring absolute top-3 right-3 inline-flex size-9 items-center justify-center rounded-md border border-transparent transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none md:top-4 md:right-4">
|
|
75
90
|
<X className="size-4.5" />
|
|
76
91
|
<span className="sr-only">Close</span>
|
|
@@ -0,0 +1,34 @@
|
|
|
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 <View className={cn("bg-card gap-4 rounded border border-border p-4", className)} {...props} />;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function CardHeader({ className, ...props }: ViewProps) {
|
|
11
|
+
return <View className={cn("gap-1", className)} {...props} />;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function CardTitle({ className, ...props }: TextProps) {
|
|
15
|
+
return <Text className={cn("text-card-foreground text-xl", className)} {...props} />;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function CardDescription({ className, ...props }: TextProps) {
|
|
19
|
+
return <Text className={cn("text-muted-foreground text-xs", className)} {...props} />;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function CardAction({ className, ...props }: ViewProps) {
|
|
23
|
+
return <View className={cn("self-start", className)} {...props} />;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function CardContent({ className, ...props }: ViewProps) {
|
|
27
|
+
return <View className={className} {...props} />;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function CardFooter({ className, ...props }: ViewProps) {
|
|
31
|
+
return <View className={cn("flex-row items-center", className)} {...props} />;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle };
|
|
@@ -0,0 +1,41 @@
|
|
|
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
CHANGED
|
@@ -9,3 +9,20 @@
|
|
|
9
9
|
export { createMakeStyles, type NamedStyles } from "./make-styles";
|
|
10
10
|
export { nativeShadows, type NativeShadowLayer } from "./shadows";
|
|
11
11
|
export { useColorMode, useThemeColors } from "./use-theme-colors";
|
|
12
|
+
export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "./card";
|
|
13
|
+
export { TextField } from "./text-field";
|
|
14
|
+
export { IconButton } from "./icon-button";
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
typography as nativeTypography,
|
|
18
|
+
spacing as nativeSpacing,
|
|
19
|
+
screenMargin as nativeScreenMargin,
|
|
20
|
+
componentSize as nativeComponentSize,
|
|
21
|
+
borderRadius as nativeBorderRadius,
|
|
22
|
+
streamItem as nativeStreamItem,
|
|
23
|
+
fontFamily as nativeFontFamily,
|
|
24
|
+
type TypographyVariant,
|
|
25
|
+
type SpacingToken,
|
|
26
|
+
type ComponentSizeToken,
|
|
27
|
+
type BorderRadiusToken,
|
|
28
|
+
} from "../styles/tokens/normalize-native";
|
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="uniwind/types" />
|
|
@@ -50,6 +50,46 @@
|
|
|
50
50
|
transform: scale(0.95);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
+
@keyframes sheet-slide-in-bottom {
|
|
54
|
+
from {
|
|
55
|
+
transform: translateY(100%);
|
|
56
|
+
opacity: 0;
|
|
57
|
+
}
|
|
58
|
+
to {
|
|
59
|
+
transform: translateY(0);
|
|
60
|
+
opacity: 1;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
@keyframes sheet-slide-out-bottom {
|
|
64
|
+
from {
|
|
65
|
+
transform: translateY(0);
|
|
66
|
+
opacity: 1;
|
|
67
|
+
}
|
|
68
|
+
to {
|
|
69
|
+
transform: translateY(100%);
|
|
70
|
+
opacity: 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
@keyframes sheet-slide-in-right {
|
|
74
|
+
from {
|
|
75
|
+
transform: translateX(100%);
|
|
76
|
+
opacity: 0;
|
|
77
|
+
}
|
|
78
|
+
to {
|
|
79
|
+
transform: translateX(0);
|
|
80
|
+
opacity: 1;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
@keyframes sheet-slide-out-right {
|
|
84
|
+
from {
|
|
85
|
+
transform: translateX(0);
|
|
86
|
+
opacity: 1;
|
|
87
|
+
}
|
|
88
|
+
to {
|
|
89
|
+
transform: translateX(100%);
|
|
90
|
+
opacity: 0;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
53
93
|
|
|
54
94
|
.data-open\:animate-in[data-open],
|
|
55
95
|
.data-open\:animate-in[data-state="open"] {
|
|
@@ -64,6 +104,38 @@
|
|
|
64
104
|
zoom-out 120ms ease-in;
|
|
65
105
|
}
|
|
66
106
|
|
|
107
|
+
[data-slot="sheet-overlay"][data-open],
|
|
108
|
+
[data-slot="sheet-overlay"][data-state="open"] {
|
|
109
|
+
animation: fade-in 400ms var(--ease-out);
|
|
110
|
+
}
|
|
111
|
+
[data-slot="sheet-overlay"][data-closed],
|
|
112
|
+
[data-slot="sheet-overlay"][data-state="closed"] {
|
|
113
|
+
/* Must stay in lockstep with [data-slot="sheet-content"]'s close duration below (both 200ms) —
|
|
114
|
+
Base UI gates the whole portal's unmount on this element's own close-animation duration, not
|
|
115
|
+
the content panel's, so a mismatch here yanks the sliding panel off mid-animation. */
|
|
116
|
+
animation: fade-out 200ms var(--ease-in);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
[data-slot="sheet-content"][data-open],
|
|
120
|
+
[data-slot="sheet-content"][data-state="open"] {
|
|
121
|
+
animation: sheet-slide-in-bottom 300ms var(--ease-drawer);
|
|
122
|
+
}
|
|
123
|
+
[data-slot="sheet-content"][data-closed],
|
|
124
|
+
[data-slot="sheet-content"][data-state="closed"] {
|
|
125
|
+
animation: sheet-slide-out-bottom 200ms var(--ease-drawer);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@media (min-width: 768px) {
|
|
129
|
+
[data-slot="sheet-content"][data-open],
|
|
130
|
+
[data-slot="sheet-content"][data-state="open"] {
|
|
131
|
+
animation: sheet-slide-in-right 300ms var(--ease-drawer);
|
|
132
|
+
}
|
|
133
|
+
[data-slot="sheet-content"][data-closed],
|
|
134
|
+
[data-slot="sheet-content"][data-state="closed"] {
|
|
135
|
+
animation: sheet-slide-out-right 200ms var(--ease-drawer);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
67
139
|
@media (prefers-reduced-motion: reduce) {
|
|
68
140
|
.animate-in,
|
|
69
141
|
.animate-out,
|
|
@@ -72,3 +144,22 @@
|
|
|
72
144
|
animation: none !important;
|
|
73
145
|
}
|
|
74
146
|
}
|
|
147
|
+
|
|
148
|
+
@media (prefers-reduced-motion: reduce) {
|
|
149
|
+
[data-slot="sheet-overlay"][data-open],
|
|
150
|
+
[data-slot="sheet-overlay"][data-state="open"] {
|
|
151
|
+
animation: fade-in 120ms var(--ease-out) !important;
|
|
152
|
+
}
|
|
153
|
+
[data-slot="sheet-overlay"][data-closed],
|
|
154
|
+
[data-slot="sheet-overlay"][data-state="closed"] {
|
|
155
|
+
animation: fade-out 120ms var(--ease-in) !important;
|
|
156
|
+
}
|
|
157
|
+
[data-slot="sheet-content"][data-open],
|
|
158
|
+
[data-slot="sheet-content"][data-state="open"] {
|
|
159
|
+
animation: fade-in var(--duration-150) var(--ease-out) !important;
|
|
160
|
+
}
|
|
161
|
+
[data-slot="sheet-content"][data-closed],
|
|
162
|
+
[data-slot="sheet-content"][data-state="closed"] {
|
|
163
|
+
animation: fade-out 120ms var(--ease-in) !important;
|
|
164
|
+
}
|
|
165
|
+
}
|
package/src/styles/index.css
CHANGED
|
@@ -43,14 +43,16 @@
|
|
|
43
43
|
animation-name: zoom-out;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
/*
|
|
47
|
-
|
|
46
|
+
/*
|
|
47
|
+
Values are generated from the DTCG source;
|
|
48
|
+
this file only names the roles consumed by web components.
|
|
49
|
+
*/
|
|
48
50
|
@theme inline {
|
|
49
51
|
--color-background: var(--background);
|
|
50
52
|
--color-foreground: var(--text-primary);
|
|
51
53
|
--color-card: var(--card);
|
|
52
54
|
--color-card-foreground: var(--text-primary);
|
|
53
|
-
--color-popover: var(--
|
|
55
|
+
--color-popover: var(--background);
|
|
54
56
|
--color-popover-foreground: var(--text-primary);
|
|
55
57
|
--color-primary: var(--primary);
|
|
56
58
|
--color-primary-foreground: var(--primary-foreground);
|
|
@@ -133,6 +133,7 @@
|
|
|
133
133
|
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
134
134
|
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
135
135
|
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
|
136
|
+
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
|
|
136
137
|
--duration-75: 75ms;
|
|
137
138
|
--duration-100: 100ms;
|
|
138
139
|
--duration-150: 150ms;
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Do not edit directly, this file was auto-generated.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
text: {
|
|
7
|
+
"large-title": {
|
|
8
|
+
fontSize: {
|
|
9
|
+
value: 34,
|
|
10
|
+
unit: "px",
|
|
11
|
+
},
|
|
12
|
+
lineHeight: {
|
|
13
|
+
value: 41,
|
|
14
|
+
unit: "px",
|
|
15
|
+
},
|
|
16
|
+
fontWeight: 700,
|
|
17
|
+
letterSpacing: {
|
|
18
|
+
value: -0.6,
|
|
19
|
+
unit: "px",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
title1: {
|
|
23
|
+
fontSize: {
|
|
24
|
+
value: 28,
|
|
25
|
+
unit: "px",
|
|
26
|
+
},
|
|
27
|
+
lineHeight: {
|
|
28
|
+
value: 34,
|
|
29
|
+
unit: "px",
|
|
30
|
+
},
|
|
31
|
+
fontWeight: 700,
|
|
32
|
+
letterSpacing: {
|
|
33
|
+
value: -0.4,
|
|
34
|
+
unit: "px",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
title2: {
|
|
38
|
+
fontSize: {
|
|
39
|
+
value: 22,
|
|
40
|
+
unit: "px",
|
|
41
|
+
},
|
|
42
|
+
lineHeight: {
|
|
43
|
+
value: 28,
|
|
44
|
+
unit: "px",
|
|
45
|
+
},
|
|
46
|
+
fontWeight: 600,
|
|
47
|
+
letterSpacing: {
|
|
48
|
+
value: -0.2,
|
|
49
|
+
unit: "px",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
headline: {
|
|
53
|
+
fontSize: {
|
|
54
|
+
value: 17,
|
|
55
|
+
unit: "px",
|
|
56
|
+
},
|
|
57
|
+
lineHeight: {
|
|
58
|
+
value: 22,
|
|
59
|
+
unit: "px",
|
|
60
|
+
},
|
|
61
|
+
fontWeight: 600,
|
|
62
|
+
letterSpacing: {
|
|
63
|
+
value: -0.1,
|
|
64
|
+
unit: "px",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
body: {
|
|
68
|
+
fontSize: {
|
|
69
|
+
value: 17,
|
|
70
|
+
unit: "px",
|
|
71
|
+
},
|
|
72
|
+
lineHeight: {
|
|
73
|
+
value: 24,
|
|
74
|
+
unit: "px",
|
|
75
|
+
},
|
|
76
|
+
fontWeight: 400,
|
|
77
|
+
letterSpacing: {
|
|
78
|
+
value: 0,
|
|
79
|
+
unit: "px",
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
callout: {
|
|
83
|
+
fontSize: {
|
|
84
|
+
value: 16,
|
|
85
|
+
unit: "px",
|
|
86
|
+
},
|
|
87
|
+
lineHeight: {
|
|
88
|
+
value: 22,
|
|
89
|
+
unit: "px",
|
|
90
|
+
},
|
|
91
|
+
fontWeight: 400,
|
|
92
|
+
letterSpacing: {
|
|
93
|
+
value: -0.1,
|
|
94
|
+
unit: "px",
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
subhead: {
|
|
98
|
+
fontSize: {
|
|
99
|
+
value: 15,
|
|
100
|
+
unit: "px",
|
|
101
|
+
},
|
|
102
|
+
lineHeight: {
|
|
103
|
+
value: 20,
|
|
104
|
+
unit: "px",
|
|
105
|
+
},
|
|
106
|
+
fontWeight: 400,
|
|
107
|
+
letterSpacing: {
|
|
108
|
+
value: 0,
|
|
109
|
+
unit: "px",
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
footnote: {
|
|
113
|
+
fontSize: {
|
|
114
|
+
value: 13,
|
|
115
|
+
unit: "px",
|
|
116
|
+
},
|
|
117
|
+
lineHeight: {
|
|
118
|
+
value: 18,
|
|
119
|
+
unit: "px",
|
|
120
|
+
},
|
|
121
|
+
fontWeight: 400,
|
|
122
|
+
letterSpacing: {
|
|
123
|
+
value: 0,
|
|
124
|
+
unit: "px",
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
caption1: {
|
|
128
|
+
fontSize: {
|
|
129
|
+
value: 12,
|
|
130
|
+
unit: "px",
|
|
131
|
+
},
|
|
132
|
+
lineHeight: {
|
|
133
|
+
value: 16,
|
|
134
|
+
unit: "px",
|
|
135
|
+
},
|
|
136
|
+
fontWeight: 400,
|
|
137
|
+
letterSpacing: {
|
|
138
|
+
value: 0,
|
|
139
|
+
unit: "px",
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
caption2: {
|
|
143
|
+
fontSize: {
|
|
144
|
+
value: 11,
|
|
145
|
+
unit: "px",
|
|
146
|
+
},
|
|
147
|
+
lineHeight: {
|
|
148
|
+
value: 14,
|
|
149
|
+
unit: "px",
|
|
150
|
+
},
|
|
151
|
+
fontWeight: 500,
|
|
152
|
+
letterSpacing: {
|
|
153
|
+
value: 0.2,
|
|
154
|
+
unit: "px",
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
display: {
|
|
158
|
+
fontSize: {
|
|
159
|
+
value: 40,
|
|
160
|
+
unit: "px",
|
|
161
|
+
},
|
|
162
|
+
lineHeight: {
|
|
163
|
+
value: 44,
|
|
164
|
+
unit: "px",
|
|
165
|
+
},
|
|
166
|
+
fontWeight: 700,
|
|
167
|
+
letterSpacing: {
|
|
168
|
+
value: -1.2,
|
|
169
|
+
unit: "px",
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
overline: {
|
|
173
|
+
fontSize: {
|
|
174
|
+
value: 11,
|
|
175
|
+
unit: "px",
|
|
176
|
+
},
|
|
177
|
+
lineHeight: {
|
|
178
|
+
value: 16,
|
|
179
|
+
unit: "px",
|
|
180
|
+
},
|
|
181
|
+
fontWeight: 500,
|
|
182
|
+
letterSpacing: {
|
|
183
|
+
value: 0.8,
|
|
184
|
+
unit: "px",
|
|
185
|
+
},
|
|
186
|
+
textTransform: "uppercase",
|
|
187
|
+
},
|
|
188
|
+
mono: {
|
|
189
|
+
fontFamily: "Menlo",
|
|
190
|
+
fontSize: {
|
|
191
|
+
value: 12,
|
|
192
|
+
unit: "px",
|
|
193
|
+
},
|
|
194
|
+
lineHeight: {
|
|
195
|
+
value: 16,
|
|
196
|
+
unit: "px",
|
|
197
|
+
},
|
|
198
|
+
fontWeight: 400,
|
|
199
|
+
letterSpacing: {
|
|
200
|
+
value: 0,
|
|
201
|
+
unit: "px",
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
space: {
|
|
206
|
+
sm: "0.5rem",
|
|
207
|
+
md: "0.75rem",
|
|
208
|
+
lg: "1rem",
|
|
209
|
+
xl: "1.5rem",
|
|
210
|
+
},
|
|
211
|
+
"screen-margin": "1rem",
|
|
212
|
+
"component-size": {
|
|
213
|
+
sm: "1rem",
|
|
214
|
+
md: "1.5rem",
|
|
215
|
+
lg: "2rem",
|
|
216
|
+
xl: "2.75rem",
|
|
217
|
+
icon: "1.25rem",
|
|
218
|
+
},
|
|
219
|
+
"border-radius": {
|
|
220
|
+
sm: "0.25rem",
|
|
221
|
+
md: "0.375rem",
|
|
222
|
+
lg: "0.5rem",
|
|
223
|
+
icon: "0.375rem",
|
|
224
|
+
},
|
|
225
|
+
"stream-item": {
|
|
226
|
+
"border-radius": "0.375rem",
|
|
227
|
+
"border-width": "1px",
|
|
228
|
+
gap: "0.5rem",
|
|
229
|
+
"icon-size": "1.5rem",
|
|
230
|
+
"min-height": "50px",
|
|
231
|
+
"padding-horizontal": "0.5rem",
|
|
232
|
+
"padding-vertical": "0.25rem",
|
|
233
|
+
},
|
|
234
|
+
"font-family": {
|
|
235
|
+
primary: "System",
|
|
236
|
+
mono: "Menlo",
|
|
237
|
+
},
|
|
238
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import nativeGenerated from "./generated/native.generated";
|
|
2
|
+
|
|
3
|
+
const toPixels = (value: string) => {
|
|
4
|
+
if (value.endsWith("rem")) return Number.parseFloat(value) * 16;
|
|
5
|
+
if (value.endsWith("px")) return Number.parseFloat(value);
|
|
6
|
+
throw new Error(`Unsupported dimension: ${value}`);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const unwrap = (v: { value: number; unit?: string } | number) =>
|
|
10
|
+
typeof v === "number" ? v : v.value;
|
|
11
|
+
|
|
12
|
+
type DimensionValue = number | { value: number; unit?: string };
|
|
13
|
+
|
|
14
|
+
const makeFlat = (raw: Record<string, unknown>) => ({
|
|
15
|
+
fontFamily: raw.fontFamily as string | undefined,
|
|
16
|
+
fontSize: unwrap(raw.fontSize as DimensionValue),
|
|
17
|
+
fontWeight: raw.fontWeight as number,
|
|
18
|
+
lineHeight: unwrap(raw.lineHeight as DimensionValue),
|
|
19
|
+
letterSpacing: unwrap(raw.letterSpacing as DimensionValue),
|
|
20
|
+
...(raw.textTransform ? { textTransform: raw.textTransform as "uppercase" | "lowercase" | "capitalize" | "none" } : {}),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const generated = nativeGenerated as unknown as {
|
|
24
|
+
text: Record<string, Record<string, unknown>>;
|
|
25
|
+
space: Record<string, string>;
|
|
26
|
+
"screen-margin": string;
|
|
27
|
+
"component-size": Record<string, string>;
|
|
28
|
+
"border-radius": Record<string, string>;
|
|
29
|
+
"stream-item": Record<string, string>;
|
|
30
|
+
"font-family": { primary: string; mono: string };
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const primaryFont = generated["font-family"].primary;
|
|
34
|
+
|
|
35
|
+
const typographyEntries = Object.entries(generated.text).map(([key, raw]) => {
|
|
36
|
+
const flat = makeFlat(raw);
|
|
37
|
+
if (!flat.fontFamily) flat.fontFamily = primaryFont;
|
|
38
|
+
return [key, flat] as const;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export const typography = Object.fromEntries(typographyEntries) as Record<
|
|
42
|
+
string,
|
|
43
|
+
{
|
|
44
|
+
fontFamily: string;
|
|
45
|
+
fontSize: number;
|
|
46
|
+
fontWeight: number;
|
|
47
|
+
lineHeight: number;
|
|
48
|
+
letterSpacing: number;
|
|
49
|
+
textTransform?: "uppercase" | "lowercase" | "capitalize" | "none";
|
|
50
|
+
}
|
|
51
|
+
>;
|
|
52
|
+
|
|
53
|
+
export type TypographyVariant = keyof typeof typography;
|
|
54
|
+
|
|
55
|
+
export const spacing = Object.fromEntries(
|
|
56
|
+
Object.entries(generated.space).map(([key, value]) => [key, toPixels(value)]),
|
|
57
|
+
) as Record<keyof typeof generated.space, number>;
|
|
58
|
+
|
|
59
|
+
export type SpacingToken = keyof typeof spacing;
|
|
60
|
+
|
|
61
|
+
export const screenMargin = toPixels(generated["screen-margin"]);
|
|
62
|
+
|
|
63
|
+
export const componentSize = Object.fromEntries(
|
|
64
|
+
Object.entries(generated["component-size"]).map(([key, value]) => [key, toPixels(value)]),
|
|
65
|
+
) as Record<keyof typeof generated["component-size"], number>;
|
|
66
|
+
|
|
67
|
+
export type ComponentSizeToken = keyof typeof componentSize;
|
|
68
|
+
|
|
69
|
+
export const borderRadius = Object.fromEntries(
|
|
70
|
+
Object.entries(generated["border-radius"]).map(([key, value]) => [key, toPixels(value)]),
|
|
71
|
+
) as Record<keyof typeof generated["border-radius"], number>;
|
|
72
|
+
|
|
73
|
+
export type BorderRadiusToken = keyof typeof borderRadius;
|
|
74
|
+
|
|
75
|
+
const rawStreamItem = generated["stream-item"];
|
|
76
|
+
export const streamItem = {
|
|
77
|
+
borderRadius: toPixels(rawStreamItem["border-radius"]),
|
|
78
|
+
borderWidth: toPixels(rawStreamItem["border-width"]),
|
|
79
|
+
gap: toPixels(rawStreamItem.gap),
|
|
80
|
+
iconSize: toPixels(rawStreamItem["icon-size"]),
|
|
81
|
+
minHeight: toPixels(rawStreamItem["min-height"]),
|
|
82
|
+
paddingHorizontal: toPixels(rawStreamItem["padding-horizontal"]),
|
|
83
|
+
paddingVertical: toPixels(rawStreamItem["padding-vertical"]),
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const fontFamily = generated["font-family"];
|
|
@@ -318,7 +318,8 @@
|
|
|
318
318
|
"$type": "cubicBezier",
|
|
319
319
|
"in": { "$value": [0.4, 0, 1, 1] },
|
|
320
320
|
"out": { "$value": [0, 0, 0.2, 1] },
|
|
321
|
-
"in-out": { "$value": [0.4, 0, 0.2, 1] }
|
|
321
|
+
"in-out": { "$value": [0.4, 0, 0.2, 1] },
|
|
322
|
+
"drawer": { "$value": [0.32, 0.72, 0, 1] }
|
|
322
323
|
},
|
|
323
324
|
"duration": {
|
|
324
325
|
"$type": "duration",
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$extensions": {
|
|
3
|
+
"org.ponti.description": "Semantic and component tokens for React Native consumers. Values reference the shared foundations so mobile stays in lockstep with web. Consumed via @ponti-studios/ui/native."
|
|
4
|
+
},
|
|
5
|
+
"space": {
|
|
6
|
+
"$type": "dimension",
|
|
7
|
+
"sm": { "$value": "{spacing-scale.2}" },
|
|
8
|
+
"md": { "$value": "{spacing-scale.3}" },
|
|
9
|
+
"lg": { "$value": "{spacing-scale.4}" },
|
|
10
|
+
"xl": { "$value": "{spacing-scale.6}" }
|
|
11
|
+
},
|
|
12
|
+
"screen-margin": {
|
|
13
|
+
"$type": "dimension",
|
|
14
|
+
"$value": "{spacing-scale.4}"
|
|
15
|
+
},
|
|
16
|
+
"component-size": {
|
|
17
|
+
"$type": "dimension",
|
|
18
|
+
"sm": { "$value": "{spacing-scale.4}" },
|
|
19
|
+
"md": { "$value": "{spacing-scale.6}" },
|
|
20
|
+
"lg": { "$value": "{spacing-scale.8}" },
|
|
21
|
+
"xl": { "$value": "{spacing-scale.11}" },
|
|
22
|
+
"icon": { "$value": "{spacing-scale.5}" }
|
|
23
|
+
},
|
|
24
|
+
"border-radius": {
|
|
25
|
+
"$type": "dimension",
|
|
26
|
+
"sm": { "$value": "{radius.sm}" },
|
|
27
|
+
"md": { "$value": "{radius.md}" },
|
|
28
|
+
"lg": { "$value": "{radius.lg}" },
|
|
29
|
+
"icon": { "$value": "{radius.md}" }
|
|
30
|
+
},
|
|
31
|
+
"stream-item": {
|
|
32
|
+
"$description": "Shared look for stream rows (time, inbox). Mirrors what the app used to hand-roll in theme.ts.",
|
|
33
|
+
"$type": "dimension",
|
|
34
|
+
"border-radius": { "$value": "{radius.md}" },
|
|
35
|
+
"border-width": { "$value": { "value": 1, "unit": "px" } },
|
|
36
|
+
"gap": { "$value": "{spacing-scale.2}" },
|
|
37
|
+
"icon-size": { "$value": "{component-size.md}" },
|
|
38
|
+
"min-height": { "$value": { "value": 50, "unit": "px" } },
|
|
39
|
+
"padding-horizontal": { "$value": "{spacing-scale.2}" },
|
|
40
|
+
"padding-vertical": { "$value": "{spacing-scale.1}" }
|
|
41
|
+
},
|
|
42
|
+
"font-family": {
|
|
43
|
+
"$type": "string",
|
|
44
|
+
"primary": { "$value": "System" },
|
|
45
|
+
"mono": { "$value": "Menlo" }
|
|
46
|
+
},
|
|
47
|
+
"text": {
|
|
48
|
+
"$description": "Apple-HIG-aligned type ramp for native editorial text.",
|
|
49
|
+
"large-title": {
|
|
50
|
+
"$type": "typography",
|
|
51
|
+
"$value": {
|
|
52
|
+
"fontSize": { "value": 34, "unit": "px" },
|
|
53
|
+
"lineHeight": { "value": 41, "unit": "px" },
|
|
54
|
+
"fontWeight": "{font-weight.bold}",
|
|
55
|
+
"letterSpacing": { "value": -0.6, "unit": "px" }
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"title1": {
|
|
59
|
+
"$type": "typography",
|
|
60
|
+
"$value": {
|
|
61
|
+
"fontSize": { "value": 28, "unit": "px" },
|
|
62
|
+
"lineHeight": { "value": 34, "unit": "px" },
|
|
63
|
+
"fontWeight": "{font-weight.bold}",
|
|
64
|
+
"letterSpacing": { "value": -0.4, "unit": "px" }
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"title2": {
|
|
68
|
+
"$type": "typography",
|
|
69
|
+
"$value": {
|
|
70
|
+
"fontSize": { "value": 22, "unit": "px" },
|
|
71
|
+
"lineHeight": { "value": 28, "unit": "px" },
|
|
72
|
+
"fontWeight": "{font-weight.semibold}",
|
|
73
|
+
"letterSpacing": { "value": -0.2, "unit": "px" }
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"headline": {
|
|
77
|
+
"$type": "typography",
|
|
78
|
+
"$value": {
|
|
79
|
+
"fontSize": { "value": 17, "unit": "px" },
|
|
80
|
+
"lineHeight": { "value": 22, "unit": "px" },
|
|
81
|
+
"fontWeight": "{font-weight.semibold}",
|
|
82
|
+
"letterSpacing": { "value": -0.1, "unit": "px" }
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"body": {
|
|
86
|
+
"$type": "typography",
|
|
87
|
+
"$value": {
|
|
88
|
+
"fontSize": { "value": 17, "unit": "px" },
|
|
89
|
+
"lineHeight": { "value": 24, "unit": "px" },
|
|
90
|
+
"fontWeight": "{font-weight.normal}",
|
|
91
|
+
"letterSpacing": { "value": 0, "unit": "px" }
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"callout": {
|
|
95
|
+
"$type": "typography",
|
|
96
|
+
"$value": {
|
|
97
|
+
"fontSize": { "value": 16, "unit": "px" },
|
|
98
|
+
"lineHeight": { "value": 22, "unit": "px" },
|
|
99
|
+
"fontWeight": "{font-weight.normal}",
|
|
100
|
+
"letterSpacing": { "value": -0.1, "unit": "px" }
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"subhead": {
|
|
104
|
+
"$type": "typography",
|
|
105
|
+
"$value": {
|
|
106
|
+
"fontSize": { "value": 15, "unit": "px" },
|
|
107
|
+
"lineHeight": { "value": 20, "unit": "px" },
|
|
108
|
+
"fontWeight": "{font-weight.normal}",
|
|
109
|
+
"letterSpacing": { "value": 0, "unit": "px" }
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"footnote": {
|
|
113
|
+
"$type": "typography",
|
|
114
|
+
"$value": {
|
|
115
|
+
"fontSize": { "value": 13, "unit": "px" },
|
|
116
|
+
"lineHeight": { "value": 18, "unit": "px" },
|
|
117
|
+
"fontWeight": "{font-weight.normal}",
|
|
118
|
+
"letterSpacing": { "value": 0, "unit": "px" }
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"caption1": {
|
|
122
|
+
"$type": "typography",
|
|
123
|
+
"$value": {
|
|
124
|
+
"fontSize": { "value": 12, "unit": "px" },
|
|
125
|
+
"lineHeight": { "value": 16, "unit": "px" },
|
|
126
|
+
"fontWeight": "{font-weight.normal}",
|
|
127
|
+
"letterSpacing": { "value": 0, "unit": "px" }
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"caption2": {
|
|
131
|
+
"$type": "typography",
|
|
132
|
+
"$value": {
|
|
133
|
+
"fontSize": { "value": 11, "unit": "px" },
|
|
134
|
+
"lineHeight": { "value": 14, "unit": "px" },
|
|
135
|
+
"fontWeight": "{font-weight.medium}",
|
|
136
|
+
"letterSpacing": { "value": 0.2, "unit": "px" }
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"display": {
|
|
140
|
+
"$type": "typography",
|
|
141
|
+
"$value": {
|
|
142
|
+
"fontSize": { "value": 40, "unit": "px" },
|
|
143
|
+
"lineHeight": { "value": 44, "unit": "px" },
|
|
144
|
+
"fontWeight": "{font-weight.bold}",
|
|
145
|
+
"letterSpacing": { "value": -1.2, "unit": "px" }
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"overline": {
|
|
149
|
+
"$type": "typography",
|
|
150
|
+
"$value": {
|
|
151
|
+
"fontSize": { "value": 11, "unit": "px" },
|
|
152
|
+
"lineHeight": { "value": 16, "unit": "px" },
|
|
153
|
+
"fontWeight": "{font-weight.medium}",
|
|
154
|
+
"letterSpacing": { "value": 0.8, "unit": "px" },
|
|
155
|
+
"textTransform": "uppercase"
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"mono": {
|
|
159
|
+
"$type": "typography",
|
|
160
|
+
"$value": {
|
|
161
|
+
"fontFamily": "{font-family.mono}",
|
|
162
|
+
"fontSize": { "value": 12, "unit": "px" },
|
|
163
|
+
"lineHeight": { "value": 16, "unit": "px" },
|
|
164
|
+
"fontWeight": "{font-weight.normal}",
|
|
165
|
+
"letterSpacing": { "value": 0, "unit": "px" }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emits ONLY the native semantic/component tokens (native.tokens.json) as a
|
|
3
|
+
* typed module. Foundations are kept in the dictionary so references resolve,
|
|
4
|
+
* but are filtered out of the output — they already ship via
|
|
5
|
+
* foundations.generated.ts.
|
|
6
|
+
*/
|
|
7
|
+
export default {
|
|
8
|
+
source: ["src/styles/tokens/source/foundations.tokens.json", "src/styles/tokens/source/native.tokens.json"],
|
|
9
|
+
platforms: {
|
|
10
|
+
typescript: {
|
|
11
|
+
transformGroup: "js",
|
|
12
|
+
buildPath: "src/styles/tokens/generated/",
|
|
13
|
+
files: [
|
|
14
|
+
{
|
|
15
|
+
destination: "native.generated.ts",
|
|
16
|
+
format: "javascript/esm",
|
|
17
|
+
options: { minify: true },
|
|
18
|
+
filter: (token) => token.filePath.includes("native.tokens.json"),
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|