@ponti-studios/ui 0.4.0 → 0.4.1
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 +14 -0
- package/package.json +25 -6
- package/src/index.ts +1 -1
- package/src/native/index.ts +11 -0
- package/src/native/make-styles.ts +32 -0
- package/src/native/shadows.ts +38 -0
- package/src/native/use-theme-colors.ts +19 -0
- package/src/styles.css +1 -3
- package/src/tokens/chart-colors.stories.tsx +9 -12
- package/src/tokens/css-vars.ts +15 -0
- package/src/tokens/generated/dark.colors.generated.ts +1 -0
- package/src/tokens/generated/dark.css +1 -0
- package/src/tokens/generated/light.colors.generated.ts +1 -0
- package/src/tokens/generated/light.css +1 -0
- package/src/tokens/index.ts +0 -8
- package/src/tokens.css +3 -0
- package/dist/index.js +0 -2466
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -25,3 +25,17 @@ pnpm config set --location=user //registry.npmjs.org/:_authToken "$NODE_AUTH_TOK
|
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
CI consumers should use a secret-backed npm token with read access.
|
|
28
|
+
|
|
29
|
+
### Ships TypeScript source, not a bundle
|
|
30
|
+
|
|
31
|
+
This package has no build output — every `exports` entry resolves to a file under `src/`. Consumers are expected to transpile the package themselves (Vite, Metro, Next, etc. all do this for workspace/npm packages by default). This is deliberate: Tailwind v4 class detection for consumers of `./styles.css` or `./tokens.css` requires an `@source` directive pointing at the installed package's `src/`, e.g.
|
|
32
|
+
|
|
33
|
+
```css
|
|
34
|
+
@source "../../../node_modules/@ponti-studios/ui/src";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Bundling the package would break that detection, since Tailwind can't scan generated/minified output for class names. `pnpm run build` only type-checks; it does not emit JS.
|
|
38
|
+
|
|
39
|
+
### `./native` subpath
|
|
40
|
+
|
|
41
|
+
`@ponti-studios/ui/native` is the only part of the package that imports `react-native`. Web consumers never pull it in; native consumers get `createMakeStyles`, `nativeShadows`, `useColorMode`, and `useThemeColors`. `react-native` is an optional peer dependency — only declare it in your own `package.json` if you actually import from this subpath.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ponti-studios/ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared UI component library for ponti-studios labs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
"access": "public"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
|
-
"dist",
|
|
18
17
|
"src",
|
|
19
18
|
"THIRD_PARTY_NOTICES.md"
|
|
20
19
|
],
|
|
21
20
|
"type": "module",
|
|
22
21
|
"sideEffects": [
|
|
23
22
|
"./src/styles.css",
|
|
23
|
+
"./src/tokens.css",
|
|
24
24
|
"./src/animations.css"
|
|
25
25
|
],
|
|
26
26
|
"exports": {
|
|
@@ -64,15 +64,24 @@
|
|
|
64
64
|
"types": "./src/tokens/index.ts",
|
|
65
65
|
"import": "./src/tokens/index.ts"
|
|
66
66
|
},
|
|
67
|
+
"./tokens/css-vars": {
|
|
68
|
+
"types": "./src/tokens/css-vars.ts",
|
|
69
|
+
"import": "./src/tokens/css-vars.ts"
|
|
70
|
+
},
|
|
71
|
+
"./native": {
|
|
72
|
+
"types": "./src/native/index.ts",
|
|
73
|
+
"import": "./src/native/index.ts"
|
|
74
|
+
},
|
|
67
75
|
"./hooks": {
|
|
68
76
|
"types": "./src/hooks/index.ts",
|
|
69
77
|
"import": "./src/hooks/index.ts"
|
|
70
78
|
},
|
|
71
79
|
"./styles.css": "./src/styles.css",
|
|
80
|
+
"./tokens.css": "./src/tokens.css",
|
|
72
81
|
"./animations.css": "./src/animations.css"
|
|
73
82
|
},
|
|
74
83
|
"scripts": {
|
|
75
|
-
"build": "
|
|
84
|
+
"build": "tsc --noEmit",
|
|
76
85
|
"dev": "vite",
|
|
77
86
|
"storybook": "style-dictionary build --config style-dictionary.dark-storybook.json && storybook dev -p 6006",
|
|
78
87
|
"check:source": "node tokens/check-source.mjs",
|
|
@@ -82,7 +91,7 @@
|
|
|
82
91
|
"typecheck": "tsc --noEmit",
|
|
83
92
|
"lint": "oxlint src --fix",
|
|
84
93
|
"format": "oxfmt src --write",
|
|
85
|
-
"prepack": "pnpm run tokens:check && pnpm run check:source && pnpm run typecheck
|
|
94
|
+
"prepack": "pnpm run tokens:check && pnpm run check:source && pnpm run typecheck"
|
|
86
95
|
},
|
|
87
96
|
"dependencies": {
|
|
88
97
|
"@base-ui/react": "^1.6.0",
|
|
@@ -115,6 +124,7 @@
|
|
|
115
124
|
"playwright": "catalog:",
|
|
116
125
|
"react": "^19.2.7",
|
|
117
126
|
"react-dom": "^19.2.7",
|
|
127
|
+
"react-native": "0.86.0",
|
|
118
128
|
"storybook": "^10.5.3",
|
|
119
129
|
"style-dictionary": "5.5.0",
|
|
120
130
|
"tailwindcss": "catalog:",
|
|
@@ -124,7 +134,16 @@
|
|
|
124
134
|
},
|
|
125
135
|
"peerDependencies": {
|
|
126
136
|
"react": "^18.2.0 || ^19.0.0",
|
|
127
|
-
"react-dom": "^18.2.0 || ^19.0.0"
|
|
137
|
+
"react-dom": "^18.2.0 || ^19.0.0",
|
|
138
|
+
"react-native": ">=0.74"
|
|
128
139
|
},
|
|
129
|
-
"packageManager": "pnpm@10.30.3"
|
|
140
|
+
"packageManager": "pnpm@10.30.3",
|
|
141
|
+
"peerDependenciesMeta": {
|
|
142
|
+
"react-dom": {
|
|
143
|
+
"optional": true
|
|
144
|
+
},
|
|
145
|
+
"react-native": {
|
|
146
|
+
"optional": true
|
|
147
|
+
}
|
|
148
|
+
}
|
|
130
149
|
}
|
package/src/index.ts
CHANGED
|
@@ -9,9 +9,9 @@ export { normalizeOtp, OTP_LENGTH } from "./lib/auth";
|
|
|
9
9
|
export { copyToClipboard } from "./lib/clipboard";
|
|
10
10
|
export { createMemoryStorage } from "./lib/create-memory-storage";
|
|
11
11
|
export { cn } from "./lib/utils";
|
|
12
|
+
export { colors } from "./tokens/css-vars";
|
|
12
13
|
export {
|
|
13
14
|
animations,
|
|
14
|
-
colors,
|
|
15
15
|
colorThemes,
|
|
16
16
|
colorTokenNames,
|
|
17
17
|
containers,
|
|
@@ -0,0 +1,11 @@
|
|
|
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 { createMakeStyles, type NamedStyles } from "./make-styles";
|
|
10
|
+
export { nativeShadows, type NativeShadowLayer } from "./shadows";
|
|
11
|
+
export { useColorMode, useThemeColors } from "./use-theme-colors";
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { shadows, type ShadowToken } from "../tokens";
|
|
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[]>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useColorScheme } from "react-native";
|
|
2
|
+
|
|
3
|
+
import { colorThemes, type ColorMode, type ColorTheme } from "../tokens";
|
|
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
|
+
}
|
package/src/styles.css
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
@import "tailwindcss";
|
|
2
|
-
@import "./tokens
|
|
3
|
-
@import "./tokens/generated/light.css";
|
|
4
|
-
@import "./tokens/generated/dark.css" (prefers-color-scheme: dark);
|
|
2
|
+
@import "./tokens.css";
|
|
5
3
|
@import "./animations.css";
|
|
6
4
|
|
|
7
5
|
/* shadcn New York semantic contract. Values are generated from the DTCG
|
|
@@ -78,16 +78,13 @@ export const CategoricalPalette: Story = {
|
|
|
78
78
|
<p className="text-muted-foreground text-sm">Foundations / charts</p>
|
|
79
79
|
<h1 className="text-4xl font-semibold tracking-tight">Chart colors</h1>
|
|
80
80
|
<p className="text-muted-foreground max-w-2xl text-base">
|
|
81
|
-
<code className="font-mono">chart-1</code> through
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
<code className="font-mono">chart-
|
|
88
|
-
chart-negative
|
|
89
|
-
</code>
|
|
90
|
-
/<code className="font-mono">chart-neutral</code> below, which carry real meaning
|
|
81
|
+
<code className="font-mono">chart-1</code> through{" "}
|
|
82
|
+
<code className="font-mono">chart-5</code> are an ordinal palette for arbitrary
|
|
83
|
+
categorical series (e.g. one line per country) — there's no fixed meaning to a given slot,
|
|
84
|
+
so they're assigned by index, not by what the data represents. That's different from{" "}
|
|
85
|
+
<code className="font-mono">chart-positive</code>/
|
|
86
|
+
<code className="font-mono">chart-negative</code>/
|
|
87
|
+
<code className="font-mono">chart-neutral</code> below, which carry real meaning
|
|
91
88
|
(up/down/flat) and should stay semantic in any chart that shows a directional delta.
|
|
92
89
|
</p>
|
|
93
90
|
</header>
|
|
@@ -112,8 +109,8 @@ export const CategoricalPalette: Story = {
|
|
|
112
109
|
<section className="border-border bg-card grid gap-5 rounded-xl border p-6">
|
|
113
110
|
<h2 className="text-2xl font-semibold">Grouped bar chart (mock)</h2>
|
|
114
111
|
<p className="text-muted-foreground max-w-2xl text-sm">
|
|
115
|
-
Three unrelated categories, five series each — a stress test for how distinguishable
|
|
116
|
-
|
|
112
|
+
Three unrelated categories, five series each — a stress test for how distinguishable the
|
|
113
|
+
palette stays side by side.
|
|
117
114
|
</p>
|
|
118
115
|
<div className="flex items-end gap-8" style={{ height: 220 }}>
|
|
119
116
|
{BAR_DATA.map((group, groupIndex) => (
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { colorTokenNames, type ColorToken } from "./index";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Color tokens as CSS `var()` references, for consumers whose runtime resolves
|
|
5
|
+
* the CSS cascade (i.e. web). Kept out of `./tokens` because React Native has
|
|
6
|
+
* no cascade — a `var(--token)` string there fails silently, rendering as an
|
|
7
|
+
* unparseable color rather than throwing.
|
|
8
|
+
*/
|
|
9
|
+
export const colors = colorTokenNames.reduce(
|
|
10
|
+
(accumulator, token) => {
|
|
11
|
+
accumulator[token] = `var(--${token})`;
|
|
12
|
+
return accumulator;
|
|
13
|
+
},
|
|
14
|
+
{} as Record<ColorToken, `var(--${string})`>,
|
|
15
|
+
);
|
package/src/tokens/index.ts
CHANGED
|
@@ -27,14 +27,6 @@ export const colorThemes = {
|
|
|
27
27
|
dark: darkTokens,
|
|
28
28
|
} as const satisfies Record<ColorMode, ColorTheme>;
|
|
29
29
|
|
|
30
|
-
export const colors = colorTokenNames.reduce(
|
|
31
|
-
(accumulator, token) => {
|
|
32
|
-
accumulator[token] = `var(--${token})`;
|
|
33
|
-
return accumulator;
|
|
34
|
-
},
|
|
35
|
-
{} as Record<ColorToken, `var(--${string})`>,
|
|
36
|
-
);
|
|
37
|
-
|
|
38
30
|
export const spacing = Object.fromEntries(
|
|
39
31
|
Object.entries(foundations["spacing-scale"]).map(([key, value]) => [
|
|
40
32
|
key.replace("-", "."),
|
package/src/tokens.css
ADDED