Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
![GitHub Issues](https://img.shields.io/github/issues/coderdiaz/jacaranda?style=flat)
![GitHub Stars](https://img.shields.io/github/stars/coderdiaz/jacaranda?style=flat)

> ⚠️ **BETA SOFTWARE**: This library is in active development and not yet recommended for production use. APIs may change without notice. Feel free to try it out and provide feedback!

Provides a way to styling components in React Native with better experience and composability. The key feature is the ability to create multi-variants styles with a type-safe definition inspired by [Stitches](https://stitches.dev/docs/variants) and [CVA](https://cva.style/docs/getting-started/variants) (for React apps).

## Features
Expand All @@ -27,7 +25,7 @@ Provides a way to styling components in React Native with better experience and
- [x] Styled function to styling component using design tokens.
- [x] Use `Stylesheet.create` instead a simple objects.
- [x] Access to `props` from styles defined into `styled` components.
- [ ] Type-safe registered tokens inside styles.
- [x] Type-safe registered tokens inside styles.
- [ ] Default design tokens.

### How to install
Expand Down Expand Up @@ -197,4 +195,4 @@ const StyledView = styled(View)((props) => ({
}));
```

Copyright @ 2025 by Javier Diaz
Copyright @ since 2025 by Javier Diaz
2 changes: 1 addition & 1 deletion packages/jacaranda/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"scripts": {
"build": "pnpm run '/^build:.*/'",
"build:cjs": "swc ./src/index.ts --config-file ./.swcrc -o dist/index.js -C module.type=commonjs",
"build:esm": "swc ./src/index.ts --config-file ./.swcrc -o dist/index.js -C module.type=es6",
"build:esm": "swc ./src/index.ts --config-file ./.swcrc -o dist/index.mjs -C module.type=es6",
"build:tsc": "tsc --project tsconfig.build.json",
"check": "tsc --project tsconfig.json --noEmit",
"prepublishOnly": "pnpm build",
Expand Down
158 changes: 157 additions & 1 deletion packages/jacaranda/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,165 @@
import React from 'react';
import { View } from 'react-native';
import { describe, it, expect } from 'vitest';
import { describe, it, expect, expectTypeOf } from 'vitest';
import { render } from '@testing-library/react-native';
import { defineTokens } from './';

describe('Type Safety - TokenPaths', () => {
it('should generate correct token paths for colors', () => {
const config = defineTokens({
colors: {
white: '#ffffff',
black: '#000000',
primary: '#06b6d4',
},
});

// Type test: verify tokens object has correct structure
expectTypeOf(config.tokens.colors).toMatchTypeOf<{
white: string;
black: string;
primary: string;
}>();
});

it('should generate correct token paths for space tokens', () => {
const config = defineTokens({
space: {
1: 4,
2: 8,
3: 12,
},
});

// Type test: verify tokens object has correct structure
expectTypeOf(config.tokens.space).toMatchTypeOf<{
1: number;
2: number;
3: number;
}>();
});

it('should generate correct token paths for multiple categories', () => {
const config = defineTokens({
colors: {
white: '#ffffff',
primary: '#06b6d4',
},
space: {
1: 4,
2: 8,
},
fontSize: {
sm: 12,
md: 16,
},
});

// Type test: verify tokens object has all categories
expectTypeOf(config.tokens.colors).toMatchTypeOf<{
white: string;
primary: string;
}>();

expectTypeOf(config.tokens.space).toMatchTypeOf<{
1: number;
2: number;
}>();

expectTypeOf(config.tokens.fontSize).toMatchTypeOf<{
sm: number;
md: number;
}>();
});

it('should work with empty token config', () => {
const config = defineTokens({});

// Type test: empty config should still work
expectTypeOf(config.tokens).toEqualTypeOf<{}>();
});

it('should provide type-safe token references in sva', () => {
const { sva } = defineTokens({
colors: {
primary: '#06b6d4',
secondary: '#8b5cf6',
},
space: {
1: 4,
2: 8,
},
});

// This should compile with valid token references
const buttonStyles = sva({
base: {
backgroundColor: '$colors.primary',
padding: '$space.1',
},
variants: {
size: {
small: { padding: '$space.1' },
large: { padding: '$space.2' },
},
},
});

// Verify it works at runtime
const result = buttonStyles({ size: 'small' });
expect(result).toEqual({
backgroundColor: '#06b6d4',
padding: 4,
});
});

it('should provide type-safe token references in styled', () => {
const { styled } = defineTokens({
colors: {
white: '#ffffff',
primary: '#06b6d4',
},
space: {
2: 8,
4: 16,
},
});

// This should compile with valid token references
const StyledView = styled(View)({
backgroundColor: '$colors.white',
padding: '$space.4',
});

// Verify the component renders
const { toJSON } = render(React.createElement(StyledView));
expect(toJSON()).toBeTruthy();
});

it('should provide readonly tokens object', () => {
const { tokens } = defineTokens({
colors: {
primary: '#06b6d4',
},
space: {
1: 4,
},
} as const);

// Type test: tokens should be readonly
expectTypeOf(tokens).toMatchTypeOf<
Readonly<{
colors?: { primary: string };
space?: { 1: number };
}>
>();

// Runtime test: tokens should be accessible
expect(tokens.colors?.primary).toBe('#06b6d4');
expect(tokens.space?.[1]).toBe(4);
});
});

describe('sva', () => {
it('should return base styles when no variants are provided', () => {
const { sva } = defineTokens({});
Expand Down
Loading