diff --git a/.changeset/cuddly-wings-travel.md b/.changeset/cuddly-wings-travel.md new file mode 100644 index 0000000..3cbb151 --- /dev/null +++ b/.changeset/cuddly-wings-travel.md @@ -0,0 +1,5 @@ +--- +'@typestyles/open-props': minor +--- + +Initial implementation diff --git a/.changeset/fix-lint-errors.md b/.changeset/fix-lint-errors.md new file mode 100644 index 0000000..d08eaa6 --- /dev/null +++ b/.changeset/fix-lint-errors.md @@ -0,0 +1,13 @@ +--- +'@typestyles/props': minor +'typestyles': minor +--- + +Fix lint errors and TypeScript issues + +- Replace `any` types with `unknown` in type definitions +- Fix empty object types `{}` in defineProperties +- Add proper generic type parameters to functions +- Prefix unused parameters with underscore +- Add eslint ignores for generated docs files and scripts +- Fix test assertions to use proper types diff --git a/docs/DOC_STRUCTURE.md b/docs/DOC_STRUCTURE.md index ad2fc44..e3a362a 100644 --- a/docs/DOC_STRUCTURE.md +++ b/docs/DOC_STRUCTURE.md @@ -1,22 +1,27 @@ # Documentation Structure ## Getting Started + - getting-started.md - api-reference.md -## Core Concepts +## Core Concepts + - styles.md - tokens.md +- open-props.md - keyframes.md - color.md ## Advanced Features + - ssr.md - vite-plugin.md - custom-at-rules.md - theming-patterns.md ## Guides + - migration.md - best-practices.md - testing.md @@ -25,6 +30,7 @@ - troubleshooting.md ## Examples & Recipes + - react-integration.md - component-library.md - design-system.md diff --git a/docs/content/docs/open-props.md b/docs/content/docs/open-props.md new file mode 100644 index 0000000..50b3830 --- /dev/null +++ b/docs/content/docs/open-props.md @@ -0,0 +1,331 @@ +--- +title: Open Props +description: Type-safe access to Open Props CSS custom properties +--- + +# Open Props + +[Open Props](https://open-props.style/) is a collection of expertly crafted CSS design tokens. This package provides type-safe access to all Open Props tokens directly in TypeScript. + +## Installation + +```bash +npm install @typestyles/open-props +``` + +## Quick Start + +```ts +import { sizes, radius, color, font } from '@typestyles/open-props'; + +const card = styles.create('card', { + padding: sizes['4'], + borderRadius: radius['3'], + backgroundColor: color['gray-2'], + fontFamily: font['sans'], +}); +``` + +All tokens return `var(--token-name)` references that work seamlessly with typestyles. + +## Available Tokens + +### Sizes + +Spacing and sizing tokens for layout: + +```ts +sizes['0']; // var(--size-0) +sizes['1']; // var(--size-1) +sizes['2']; // var(--size-2) +sizes['3']; // var(--size-3) +sizes['4']; // var(--size-4) +// ... up to sizes['10'] + +// Fluid sizes +sizes['fluid-1']; // var(--size-fluid-1) +sizes['fluid-2']; // var(--size-fluid-2) +sizes['fluid-3']; // var(--size-fluid-3) + +// Content sizes +sizes['content-1']; // 20ch +sizes['content-2']; // 45ch +sizes['content-3']; // 60ch +``` + +### Radius + +Border radius tokens: + +```ts +radius['0']; // var(--radius-0) +radius['1']; // var(--radius-1) +radius['2']; // var(--radius-2) +radius['3']; // var(--radius-3) +radius['4']; // var(--radius-4) +// ... up to radius['30'] + +// Special values +radius['round']; // 100% +radius['pill']; // 9999px +``` + +### Colors + +19 color scales with 13 shades each (0-12): + +```ts +// Access by color name and shade +color['gray-0']; // var(--color-gray-0) +color['gray-5']; // var(--color-gray-5) +color['gray-10']; // var(--color-gray-10) + +color['indigo-0']; // var(--color-indigo-0) +color['blue-6']; // var(--color-blue-6) +color['red-4']; // var(--color-red-4) +``` + +Available color palettes: + +- `gray`, `stone`, `red`, `pink`, `purple`, `violet`, `indigo`, `blue` +- `cyan`, `teal`, `green`, `lime`, `yellow`, `orange` +- `choco`, `brown`, `sand`, `camo`, `jungle` + +### Typography + +```ts +// Font sizes +fontSize['00']; // 0.5rem +fontSize['0']; // 0.75rem +fontSize['1']; // 1rem +fontSize['2']; // 1.1rem +// ... up to fontSize['8'] + +// Fluid font sizes +fontSize['fluid-0']; // clamp(0.75rem, 2vw, 1rem) +fontSize['fluid-1']; // clamp(1rem, 4vw, 1.5rem) +fontSize['fluid-2']; // clamp(1.5rem, 6vw, 2.5rem) +fontSize['fluid-3']; // clamp(2rem, 9vw, 3.5rem) + +// Font weights +fontWeight['1']; // 100 +fontWeight['4']; // 400 +fontWeight['7']; // 700 +fontWeight['9']; // 900 + +// Letter spacing +fontLetterspacing['0']; // -.05em +fontLetterspacing['4']; // .150em + +// Line height +fontLineheight['00']; // .95 +fontLineheight['1']; // 1.25 +fontLineheight['3']; // 1.5 + +// Font families +font['sans']; // var(--font-sans) +font['serif']; // var(--font-serif) +font['mono']; // var(--font-mono) +font['system-ui']; // var(--font-system-ui) +font['humanist']; // var(--font-humanist) +// ... and more +``` + +### Shadows + +```ts +shadow['1']; // var(--shadow-1) +shadow['2']; // var(--shadow-2) +shadow['3']; // var(--shadow-3) +shadow['4']; // var(--shadow-4) +shadow['5']; // var(--shadow-5) +shadow['6']; // var(--shadow-6) + +// Inner shadows +shadow['inner-1']; // var(--shadow-inner-1) +shadow['inner-2']; // var(--shadow-inner-2) +shadow['inner-3']; // var(--shadow-inner-3) +shadow['inner-4']; // var(--shadow-inner-4) +shadow['inner-5']; // var(--shadow-inner-5) +``` + +### Gradients + +30 handcrafted gradients: + +```ts +gradient['1']; // var(--gradient-1) +gradient['10']; // var(--gradient-10) +gradient['20']; // var(--gradient-20) +gradient['30']; // var(--gradient-30) +``` + +### Easing + +CSS easing functions: + +```ts +easing['1']; // var(--ease-1) +easing['2']; // var(--ease-2) +easing['3']; // var(--ease-3) + +// Directional +easing['in-1']; // var(--ease-in-1) +easing['out-1']; // var(--ease-out-1) +easing['in-out-1']; // var(--ease-in-out-1) + +// Elastic +easing['elastic-out-1']; // var(--ease-elastic-out-1) +easing['elastic-in-1']; // var(--ease-elastic-in-1) + +// Bounce +easing['bounce-1']; // var(--ease-bounce-1) +``` + +### Animations + +Pre-defined animation names: + +```ts +animation['fade-in']; // var(--animation-fade-in) +animation['slide-in-up']; // var(--animation-slide-in-up) +animation['scale-in']; // var(--animation-scale-in) +animation['spin']; // var(--animation-spin) +animation['pulse']; // var(--animation-pulse) +// ... and more +``` + +### Media Queries + +Media query conditions for responsive design: + +```ts +media['motion']; // var(--media-motion) +media['motionReduce']; // var(--media-motionReduce) +media['dark']; // var(--media-dark) +media['light']; // var(--media-light) +media['landscape']; // var(--media-landscape) +media['portrait']; // var(--media-portrait) + +// Breakpoints +media['sm']; // var(--media-sm) - 24rem +media['md']; // var(--media-md) - 28rem +media['lg']; // var(--media-lg) - 32rem +media['xl']; // var(--media-xl) - 36rem +media['2xl']; // var(--media-2xl) - 42rem +// ... up to media['9xl'] +``` + +### Other Tokens + +```ts +// Aspect ratios +ratio['square']; // var(--ratio-square) +ratio['landscape']; // var(--ratio-landscape) +ratio['portrait']; // var(--ratio-portrait) +ratio['widescreen']; // var(--ratio-widescreen) +ratio['golden']; // var(--ratio-golden) + +// Z-index layers +zIndex['1']; // var(--zindex-1) +zIndex['max']; // var(--zindex-max) + +// Durations +duration['0']; // 0s +duration['1']; // 0.05s +duration['2']; // 0.1s +duration['3']; // 0.2s +duration['4']; // 0.4s +duration['5']; // 0.8s + +// Border widths +borderSize['0']; // 0 +borderSize['1']; // 1px +borderSize['2']; // 2px +// ... and more +``` + +### Brand Colors + +Brand-specific colors for common services: + +```ts +brand['facebook']; // var(--brand-facebook) +brand['twitter']; // var(--brand-twitter) +brand['instagram']; // var(--brand-instagram) +brand['youtube']; // var(--brand-youtube) +brand['spotify']; // var(--brand-spotify) +brand['discord']; // var(--brand-discord) +// ... and more +``` + +### Palette + +Dynamic OKLCH palette for creating custom color schemes: + +```ts +palette['1']; // var(--palette-1) +palette['8']; // var(--palette-8) +palette['16']; // var(--palette-16) +``` + +### Masks + +SVG mask presets: + +```ts +masksEdges['0']; // var(--masks-edge-0) +masksEdges['4']; // var(--masks-edge-4) + +masksCornerCuts['1']; // var(--masks-corner-cuts-1) +masksCornerCuts['6']; // var(--masks-corner-cuts-6) +``` + +## Using with Styles + +All tokens work seamlessly with typestyles: + +```ts +import { styles } from 'typestyles'; +import { sizes, radius, color, shadow, fontSize } from '@typestyles/open-props'; + +const button = styles.create('button', { + display: 'inline-flex', + alignItems: 'center', + justifyContent: 'center', + padding: `${sizes['2']} ${sizes['4']}`, + borderRadius: radius['2'], + fontSize: fontSize['2'], + backgroundColor: color['blue-6'], + color: color['blue-0'], + boxShadow: shadow['2'], + transition: 'all 200ms var(--ease-2)', + + '&:hover': { + boxShadow: shadow['3'], + backgroundColor: color['blue-5'], + }, +}); +``` + +## Combining with Custom Tokens + +You can mix Open Props with your own custom tokens: + +```ts +import { tokens } from 'typestyles'; +import { color, sizes } from '@typestyles/open-props'; + +// Your custom tokens +const brand = tokens.create('brand', { + primary: '#ff6b6b', + accent: '#4ecdc4', +}); + +// Use both together +const container = styles.create('container', { + backgroundColor: brand.primary, // var(--brand-primary) + padding: sizes['4'], // var(--size-4) + borderColor: color['gray-3'], // var(--color-gray-3) +}); +``` diff --git a/eslint.config.js b/eslint.config.js index 29e8c53..7026839 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -7,7 +7,14 @@ export default tseslint.config( ...tseslint.configs.recommended, prettier, { - ignores: ['**/dist/**', '**/node_modules/**', '**/coverage/**', '**/.turbo/**'], + ignores: [ + '**/dist/**', + '**/node_modules/**', + '**/coverage/**', + '**/.turbo/**', + 'docs/.content-collections/**', + 'scripts/**', + ], }, { rules: { diff --git a/package.json b/package.json index 4dfb4ef..98213ed 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "format:check": "prettier --check .", "changeset": "changeset", "version": "changeset version", - "release": "turbo build --filter=\"typestyles\" --filter=\"@typestyles/vite\" && changeset publish", + "release": "turbo build && changeset publish", "prepare": "husky" }, "devDependencies": { diff --git a/packages/open-props/package.json b/packages/open-props/package.json new file mode 100644 index 0000000..74b0d9a --- /dev/null +++ b/packages/open-props/package.json @@ -0,0 +1,47 @@ +{ + "name": "@typestyles/open-props", + "version": "0.1.0", + "description": "Type-safe Open Props integration for typestyles", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } + }, + "./css": { + "default": "./dist/open-props.css" + } + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsup", + "test": "vitest run", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "open-props": "^1.7.0", + "typestyles": "workspace:*" + }, + "devDependencies": { + "tsup": "^8.0.0", + "typescript": "^5.9.3", + "vitest": "^3.0.0" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/dbanksdesign/typestyles", + "directory": "packages/open-props" + } +} diff --git a/packages/open-props/src/index.ts b/packages/open-props/src/index.ts new file mode 100644 index 0000000..895be36 --- /dev/null +++ b/packages/open-props/src/index.ts @@ -0,0 +1,720 @@ +import { tokens, type TokenRef } from 'typestyles'; + +export { tokens }; +export type { TokenRef }; + +export const sizes = tokens.create('size', { + '0': '0', + '1': '0.25rem', + '2': '0.5rem', + '3': '0.75rem', + '4': '1rem', + '5': '1.25rem', + '6': '1.5rem', + '7': '2rem', + '8': '3rem', + '9': '4rem', + '10': '5rem', + 'content-1': '20ch', + 'content-2': '45ch', + 'content-3': '60ch', + 'fluid-1': 'clamp(0.5rem, 2vw, 1rem)', + 'fluid-2': 'clamp(1rem, 4vw, 1.5rem)', + 'fluid-3': 'clamp(1.5rem, 6vw, 2rem)', + 'fluid-4': 'clamp(2rem, 8vw, 3rem)', + 'fluid-5': 'clamp(3rem, 12vw, 5rem)', + 'fluid-6': 'clamp(5rem, 20vw, 8rem)', + 'fluid-7': 'clamp(8rem, 30vw, 12rem)', + 'fluid-8': 'clamp(12rem, 40vw, 20rem)', +}); + +export const radius = tokens.create('radius', { + '0': '0', + '1': '2px', + '2': '4px', + '3': '8px', + '4': '12px', + '5': '16px', + '6': '20px', + '7': '24px', + '8': '32px', + '9': '40px', + '10': '48px', + '11': '56px', + '12': '64px', + '13': '72px', + '14': '80px', + '15': '88px', + '16': '96px', + '17': '104px', + '18': '112px', + '19': '120px', + '20': '128px', + '21': '136px', + '22': '144px', + '23': '152px', + '24': '160px', + '25': '168px', + '26': '176px', + '27': '184px', + '28': '192px', + '29': '200px', + '30': '208px', + round: '100%', + pill: '9999px', +}); + +export const shadow = tokens.create('shadow', { + '1': '0 1px 2px 0 rgb(0 0 0 / 0.05)', + '2': '0 2px 4px 0 rgb(0 0 0 / 0.05), 0 4px 8px 0 rgb(0 0 0 / 0.05)', + '3': '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)', + '4': '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)', + '5': '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)', + '6': '0 25px 50px -12px rgb(0 0 0 / 0.25)', + 'inner-1': 'inset 0 1px 2px 0 rgb(0 0 0 / 0.05)', + 'inner-2': 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05), inset 0 4px 8px 0 rgb(0 0 0 / 0.05)', + 'inner-3': 'inset 0 4px 6px -1px rgb(0 0 0 / 0.1), inset 0 2px 4px -2px rgb(0 0 0 / 0.1)', + 'inner-4': 'inset 0 10px 15px -3px rgb(0 0 0 / 0.1), inset 0 4px 6px -4px rgb(0 0 0 / 0.1)', + 'inner-5': 'inset 0 20px 25px -5px rgb(0 0 0 / 0.1), inset 0 8px 10px -6px rgb(0 0 0 / 0.1)', +}); + +export const easing = tokens.create('ease', { + '1': '0.25, 0.1, 0.25, 1', + '2': '0.42, 0, 1, 1', + '3': '0, 0, 0.58, 1', + '4': '0.42, 0, 0.58, 1', + '5': '0.25, 0.1, 0.25, 1', + 'in-1': '0.25, 0.1, 0.25, 1', + 'in-2': '0.42, 0, 1, 1', + 'in-3': '0, 0, 0.58, 1', + 'in-4': '0.42, 0, 0.58, 1', + 'in-5': '0.25, 0.1, 0.25, 1', + 'out-1': '0.25, 0.1, 0.25, 1', + 'out-2': '0.42, 0, 1, 1', + 'out-3': '0, 0, 0.58, 1', + 'out-4': '0.42, 0, 0.58, 1', + 'out-5': '0.25, 0.1, 0.25, 1', + 'in-out-1': '0.25, 0.1, 0.25, 1', + 'in-out-2': '0.42, 0, 1, 1', + 'in-out-3': '0, 0, 0.58, 1', + 'in-out-4': '0.42, 0, 0.58, 1', + 'in-out-5': '0.25, 0.1, 0.25, 1', + 'elastic-out-1': '0.31, 0.24, 0.37, 1.04', + 'elastic-out-2': '0.47, 0.27, 0.11, 1.07', + 'elastic-out-3': '0.58, 0.27, 0.11, 1', + 'elastic-out-4': '0.65, 0.28, 0.11, 1', + 'elastic-out-5': '0.7, 0.28, 0.11, 1', + 'elastic-in-1': '0.71, -0.01, 0.88, 0.77', + 'elastic-in-2': '0.93, -0.17, 0.75, 0.75', + 'elastic-in-3': '0.77, 0, 0.18, 1', + 'elastic-in-4': '0.95, -0.05, 0.71, 0.97', + 'elastic-in-5': '0.96, -0.05, 0.69, 1', + 'elastic-in-out-1': '0.68, -0.55, 0.27, 1.55', + 'elastic-in-out-2': '0.68, -0.55, 0.27, 1.55', + 'elastic-in-out-3': '0.68, -0.55, 0.27, 1.55', + 'elastic-in-out-4': '0.68, -0.55, 0.27, 1.55', + 'elastic-in-out-5': '0.68, -0.55, 0.27, 1.55', + 'bounce-1': '0.45, 0.05, 0.55, 0.95', + 'bounce-2': '0.45, 0.05, 0.55, 0.95', + 'bounce-3': '0.45, 0.05, 0.55, 0.95', + 'bounce-4': '0.45, 0.05, 0.55, 0.95', + 'bounce-5': '0.45, 0.05, 0.55, 0.95', +}); + +export const animation = tokens.create('animation', { + 'fade-in': 'fade-in 0.5s var(--ease-3)', + 'fade-out': 'fade-out 0.5s var(--ease-3)', + 'scale-in': 'scale-in 0.2s var(--ease-3)', + 'scale-out': 'scale-out 0.2s var(--ease-3)', + 'slide-in-up': 'slide-in-up 0.3s var(--ease-out-5)', + 'slide-in-down': 'slide-in-down 0.3s var(--ease-out-5)', + 'slide-in-left': 'slide-in-left 0.3s var(--ease-out-5)', + 'slide-in-right': 'slide-in-right 0.3s var(--ease-out-5)', + 'slide-out-up': 'slide-out-up 0.3s var(--ease-in-5)', + 'slide-out-down': 'slide-out-down 0.3s var(--ease-in-5)', + 'slide-out-left': 'slide-out-left 0.3s var(--ease-in-5)', + 'slide-out-right': 'slide-out-right 0.3s var(--ease-in-5)', + shake: 'shake 0.5s cubic-bezier(.36,.07,.19,.97) both', + bounce: 'bounce 1s infinite', + spin: 'spin 2s linear infinite', + flip: 'flip 1s ease-in-out infinite', + float: 'float 3s ease-in-out infinite', + jiggle: 'jiggle 1s ease-in-out infinite', + wiggle: 'wiggle 1s ease-in-out infinite', + pulse: 'pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite', + pop: 'pop 0.3s var(--ease-out-4)', +}); + +export const fontSize = tokens.create('font-size', { + '00': '0.5rem', + '0': '0.75rem', + '1': '1rem', + '2': '1.1rem', + '3': '1.25rem', + '4': '1.5rem', + '5': '2rem', + '6': '2.5rem', + '7': '3rem', + '8': '3.5rem', + 'fluid-0': 'clamp(0.75rem, 2vw, 1rem)', + 'fluid-1': 'clamp(1rem, 4vw, 1.5rem)', + 'fluid-2': 'clamp(1.5rem, 6vw, 2.5rem)', + 'fluid-3': 'clamp(2rem, 9vw, 3.5rem)', +}); + +export const fontWeight = tokens.create('font-weight', { + '1': '100', + '2': '200', + '3': '300', + '4': '400', + '5': '500', + '6': '600', + '7': '700', + '8': '800', + '9': '900', +}); + +export const fontLetterspacing = tokens.create('font-letterspacing', { + '0': '-.05em', + '1': '.025em', + '2': '.050em', + '3': '.075em', + '4': '.150em', + '5': '.500em', + '6': '.750em', + '7': '1em', +}); + +export const fontLineheight = tokens.create('font-lineheight', { + '00': '.95', + '0': '1.1', + '1': '1.25', + '2': '1.375', + '3': '1.5', + '4': '1.75', + '5': '2', +}); + +export const zIndex = tokens.create('zindex', { + '1': '100', + '2': '200', + '3': '300', + '4': '400', + '5': '500', + max: '9999', +}); + +export const ratio = tokens.create('ratio', { + square: '1', + landscape: '4/3', + portrait: '3/4', + widescreen: '16/9', + ultrawide: '18/5', + golden: '1.6180/1', +}); + +export const gradient = tokens.create('gradient', { + '1': 'linear-gradient(to bottom right, #e0e7ff, #faf5ff, #f0fdfa)', + '2': 'linear-gradient(to bottom right, #e0e7ff, #f5f3ff, #fdf4ff)', + '3': 'linear-gradient(to bottom right, #e0e7ff, #f5f3ff, #faf5ff)', + '4': 'linear-gradient(to bottom right, #c7d2fe, #e9d5ff, #f5d0fe)', + '5': 'linear-gradient(to bottom right, #e0e7ff, #ddd6fe, #c4b5fd)', + '6': 'linear-gradient(to bottom right, #c7d2fe, #ddd6fe, #c4b5fd)', + '7': 'linear-gradient(to bottom right, #a5b4fc, #c4b5fd, #ddb6f2)', + '8': 'linear-gradient(to bottom right, #a5b4fc, #a78bfa, #c4b5fd)', + '9': 'linear-gradient(to bottom right, #818cf8, #a78bfa, #c084fc)', + '10': 'linear-gradient(to bottom right, #818cf8, #a78bfa, #c4b5fd)', + '11': 'linear-gradient(to bottom right, #6366f1, #8b5cf6, #a855f7)', + '12': 'linear-gradient(to bottom right, #6366f1, #7c3aed, #8b5cf6)', + '13': 'linear-gradient(to bottom right, #4f46e5, #7c3aed, #9333ea)', + '14': 'linear-gradient(to bottom right, #4f46e5, #6d28d9, #9333ea)', + '15': 'linear-gradient(to bottom right, #4338ca, #5b21b6, #7e22ce)', + '16': 'linear-gradient(to bottom right, #3730a3, #4c1d95, #6b21a8)', + '17': 'linear-gradient(to bottom right, #312e81, #4c1d95, #6b21a8)', + '18': 'linear-gradient(to bottom right, #312e81, #3b0764, #581c87)', + '19': 'linear-gradient(to bottom right, #1e1b4b, #2e1065, #4a044e)', + '20': 'linear-gradient(to bottom right, #172554, #3b0764, #500724)', + '21': 'linear-gradient(to bottom right, #172554, #701a75, #9f1239)', + '22': 'linear-gradient(to bottom right, #0f172a, #831843, #9f1239)', + '23': 'linear-gradient(to bottom right, #0f172a, #831843, #be123c)', + '24': 'linear-gradient(to bottom right, #020617, #881337, #be123c)', + '25': 'linear-gradient(to bottom right, #020617, #9f1239, #e11d48)', + '26': 'linear-gradient(to bottom right, #030712, #9f1239, #e11d48)', + '27': 'linear-gradient(to bottom right, #030712, #be123c, #fb7185)', + '28': 'linear-gradient(to bottom right, #030712, #881337, #fda4af)', + '29': 'linear-gradient(to bottom right, #030712, #4a044e, #f0abfc)', + '30': 'linear-gradient(to bottom right, #030712, #2e1065, #c4b5fd)', +}); + +export const media = tokens.create('media', { + motion: '(prefers-reduced-motion: no-preference)', + motionReduce: '(prefers-reduced-motion: reduce)', + dark: '(prefers-color-scheme: dark)', + light: '(prefers-color-scheme: light)', + landscape: '(orientation: landscape)', + portrait: '(orientation: portrait)', + xs: '(min-width: 20rem)', + sm: '(min-width: 24rem)', + md: '(min-width: 28rem)', + lg: '(min-width: 32rem)', + xl: '(min-width: 36rem)', + '2xl': '(min-width: 42rem)', + '3xl': '(min-width: 48rem)', + '4xl': '(min-width: 56rem)', + '5xl': '(min-width: 64rem)', + '6xl': '(min-width: 72rem)', + '7xl': '(min-width: 80rem)', + '8xl': '(min-width: 96rem)', + '9xl': '(min-width: 100rem)', +}); + +export const duration = tokens.create('duration', { + '0': '0s', + '1': '0.05s', + '2': '0.1s', + '3': '0.2s', + '4': '0.4s', + '5': '0.8s', +}); + +export const borderSize = tokens.create('border-size', { + '0': '0', + '1': '1px', + '2': '2px', + '3': '4px', + '4': '8px', + '5': '16px', +}); + +export const noise = tokens.create('noise', { + '1': 'url("data:image/svg+xml,")', + '2': 'url("data:image/svg+xml,")', + '3': 'url("data:image/svg+xml,")', + '4': 'url("data:image/svg+xml,")', + '5': 'url("data:image/svg+xml,")', + 'filter-1': 'contrast(1.5) brightness(1.1)', + 'filter-2': 'contrast(1.5) brightness(1.1)', + 'filter-3': 'contrast(1.5) brightness(1.1)', + 'filter-4': 'contrast(1.5) brightness(1.1)', + 'filter-5': 'contrast(1.5) brightness(1.1)', +}); + +const colorValues: Record = {}; + +const colors = [ + 'gray', + 'stone', + 'red', + 'pink', + 'purple', + 'violet', + 'indigo', + 'blue', + 'cyan', + 'teal', + 'green', + 'lime', + 'yellow', + 'orange', + 'choco', + 'brown', + 'sand', + 'camo', + 'jungle', +]; +const colorScales: Record = { + gray: [ + '#f8fafc', + '#f1f5f9', + '#e2e8f0', + '#cbd5e1', + '#94a3b8', + '#64748b', + '#475569', + '#334155', + '#1e293b', + '#0f172a', + '#020617', + '#000000', + '#000000', + ], + stone: [ + '#fafaf9', + '#f5f5f4', + '#e7e5e4', + '#d6d3d1', + '#a8a29e', + '#78716c', + '#57534e', + '#44403c', + '#292524', + '#1c1917', + '#0c0a09', + '#000000', + '#000000', + ], + red: [ + '#fef2f2', + '#fee2e2', + '#fecaca', + '#fca5a5', + '#f87171', + '#ef4444', + '#dc2626', + '#b91c1c', + '#991b1b', + '#7f1d1d', + '#450a0a', + '#000000', + '#000000', + ], + pink: [ + '#fdf2f8', + '#fce7f3', + '#fbcfe8', + '#f9a8d4', + '#f472b6', + '#ec4899', + '#db2777', + '#be185d', + '#9d174d', + '#831843', + '#500724', + '#000000', + '#000000', + ], + purple: [ + '#faf5ff', + '#f3e8ff', + '#e9d5ff', + '#d8b4fe', + '#c084fc', + '#a855f7', + '#9333ea', + '#7e22ce', + '#6b21a8', + '#581c87', + '#3b0764', + '#000000', + '#000000', + ], + violet: [ + '#f5f3ff', + '#ede9fe', + '#ddd6fe', + '#c4b5fd', + '#a78bfa', + '#8b5cf6', + '#7c3aed', + '#6d28d9', + '#5b21b6', + '#4c1d95', + '#2e1065', + '#000000', + '#000000', + ], + indigo: [ + '#eef2ff', + '#e0e7ff', + '#c7d2fe', + '#a5b4fc', + '#818cf8', + '#6366f1', + '#4f46e5', + '#4338ca', + '#3730a3', + '#312e81', + '#1e1b4b', + '#000000', + '#000000', + ], + blue: [ + '#eff6ff', + '#dbeafe', + '#bfdbfe', + '#93c5fd', + '#60a5fa', + '#3b82f6', + '#2563eb', + '#1d4ed8', + '#1e40af', + '#1e3a8a', + '#172554', + '#000000', + '#000000', + ], + cyan: [ + '#ecfeff', + '#cffafe', + '#a5f3fc', + '#67e8f9', + '#22d3ee', + '#06b6d4', + '#0891b2', + '#0e7490', + '#155e75', + '#164e63', + '#083344', + '#000000', + '#000000', + ], + teal: [ + '#f0fdfa', + '#ccfbf1', + '#99f6e4', + '#5eead4', + '#2dd4bf', + '#14b8a6', + '#0d9488', + '#0f766e', + '#115e59', + '#134e4a', + '#042f2e', + '#000000', + '#000000', + ], + green: [ + '#f0fdf4', + '#dcfce7', + '#bbf7d0', + '#86efac', + '#4ade80', + '#22c55e', + '#16a34a', + '#15803d', + '#166534', + '#14532d', + '#052e16', + '#000000', + '#000000', + ], + lime: [ + '#f7fee7', + '#ecfccb', + '#d9f99d', + '#bef264', + '#a3e635', + '#84cc16', + '#65a30d', + '#4d7c0f', + '#3f6212', + '#365314', + '#1a2e05', + '#000000', + '#000000', + ], + yellow: [ + '#fefce8', + '#fef9c3', + '#fef08a', + '#fde047', + '#facc15', + '#eab308', + '#ca8a04', + '#a16207', + '#854d0e', + '#713f12', + '#422006', + '#000000', + '#000000', + ], + orange: [ + '#fff7ed', + '#ffedd5', + '#fed7aa', + '#fdba74', + '#fb923c', + '#f97316', + '#ea580c', + '#c2410c', + '#9a3412', + '#7c2d12', + '#431407', + '#000000', + '#000000', + ], + choco: [ + '#fefae7', + '#f7f3d8', + '#eee4b8', + '#e2d28a', + '#d6be66', + '#cba84a', + '#bc8f3c', + '#9f742e', + '#825a22', + '#664118', + '#4a2d0f', + '#000000', + '#000000', + ], + brown: [ + '#faf8f5', + '#f0ebe3', + '#e3d6c8', + '#d2bba3', + '#be9d7d', + '#ab825e', + '#956843', + '#7a4f2d', + '#5f3a1c', + '#47280f', + '#2e1605', + '#000000', + '#000000', + ], + sand: [ + '#fcfbf9', + '#f5f2ed', + '#e8e4db', + '#d6d1c3', + '#bfb6a3', + '#a69682', + '#8d7a65', + '#756151', + '#5d4a3e', + '#47382e', + '#31241d', + '#000000', + '#000000', + ], + camo: [ + '#f5f5f0', + '#e8e8dd', + '#d4d4c4', + '#b5b5a2', + '#989878', + '#7c7d5e', + '#626449', + '#4d4e38', + '#3b3c2c', + '#2c2c21', + '#1c1c14', + '#000000', + '#000000', + ], + jungle: [ + '#f3f7f2', + '#e2ebe1', + '#c5d9c6', + '#9fc1a3', + '#7aa67d', + '#5c8c60', + '#46734a', + '#375b3b', + '#2b472e', + '#213624', + '#152217', + '#000000', + '#000000', + ], +}; + +for (const colorName of colors) { + const scale = colorScales[colorName]; + if (scale) { + scale.forEach((value, index) => { + colorValues[`${colorName}-${index}`] = value; + }); + } +} + +export const color = tokens.create('color', colorValues); + +export const brand = tokens.create('brand', { + facebook: '#1877f2', + youtube: '#ff0000', + twitter: '#1da1f2', + whatsapp: '#25d366', + instagram: '#c13584', + 'instagram-yellow': '#fccc63', + 'instagram-red': '#f56040', + 'instagram-magenta': '#c13584', + 'instagram-blue': '#405de6', + snapchat: '#fffc00', + google: '#4285f4', + 'google-blue': '#4285f4', + 'google-red': '#ea4335', + 'google-yellow': '#fbbc05', + 'google-green': '#34a853', + tiktok: '#000000', + 'tiktok-razzmatazz': '#fe2c55', + 'tiktok-splash': '#25f4ee', + microsoft: '#00a4ef', + 'microsoft-blue': '#00a4ef', + 'microsoft-red': '#f25022', + 'microsoft-green': '#7fba00', + 'microsoft-yellow': '#ffb900', + pinterest: '#e60023', + spotify: '#1db954', + discord: '#5865f2', + telegram: '#0088cc', + reddit: '#ff4500', + amazon: '#ff9900', + twitch: '#9146ff', +}); + +export const font = tokens.create('font', { + 'system-ui': 'system-ui, sans-serif', + transitional: 'Charter, Bitstream Charter, Sitka Text, Cambria, serif', + 'old-style': 'Iowan Old Style, Palatino Linotype, URW Palladio L, P052, serif', + humanist: 'Seravek, Gill Sans Nova, Ubuntu, Calibri, DejaVu Sans, source-sans-pro, sans-serif', + 'geometric-humanist': 'Avenir, Montserrat, Corbel, URW Gothic, source-sans-pro, sans-serif', + 'classical-humanist': 'Optima, Candara, Noto Sans, source-sans-pro, sans-serif', + 'neo-grotesque': 'Inter, Roboto, Helvetica Neue, Arial Nova, Nimbus Sans, Arial, sans-serif', + 'monospace-slab-serif': 'Nimbus Mono PS, Courier New, monospace', + 'monospace-code': + 'Dank Mono, Operator Mono, Inconsolata, Fira Mono, ui-monospace, SF Mono, Monaco, Droid Sans Mono, Source Code Pro, Cascadia Code, Menlo, Consolas, DejaVu Sans Mono, monospace', + industrial: + 'Bahnschrift, DIN Alternate, Franklin Gothic Medium, Nimbus Sans Narrow, sans-serif-condensed, sans-serif', + 'rounded-sans': + 'ui-rounded, Hiragino Maru Gothic ProN, Quicksand, Comfortaa, Manjari, Arial Rounded MT, Arial Rounded MT Bold, Calibri, source-sans-pro, sans-serif', + 'slab-serif': 'Rockwell, Rockwell Nova, Roboto Slab, DejaVu Serif, Sitka Small, serif', + antique: + 'Superclarendon, Bookman Old Style, URW Bookman, URW Bookman L, Georgia Pro, Georgia, serif', + didone: 'Didot, Bodoni MT, Noto Serif Display, URW Palladio L, P052, Sylfaen, serif', + handwritten: 'Segoe Print, Bradley Hand, Chilanka, TSCu_Comic, casual, cursive', + sans: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif', + serif: 'Georgia, Cambria, "Times New Roman", Times, serif', + mono: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace', +}); + +export const palette = tokens.create('palette', { + '1': 'oklch(97% .014 260)', + '2': 'oklch(94% .028 261)', + '3': 'oklch(88% .057 261)', + '4': 'oklch(81% .081 262)', + '5': 'oklch(73% .12 262)', + '6': 'oklch(65% .15 262)', + '7': 'oklch(56% .19 262)', + '8': 'oklch(50% .22 262)', + '9': 'oklch(45% .24 261)', + '10': 'oklch(40% .24 259)', + '11': 'oklch(35% .22 259)', + '12': 'oklch(32% .2 259)', + '13': 'oklch(30% .18 259)', + '14': 'oklch(30% .16 259)', + '15': 'oklch(29% .14 259)', + '16': 'oklch(27% .12 259)', +}); + +export const masksEdges = tokens.create('masks-edge', { + '0': 'linear-gradient(to right, #000 90%, transparent 90% 100%)', + '1': 'linear-gradient(to right, #000 80%, transparent 80% 100%)', + '2': 'linear-gradient(to right, #000 70%, transparent 70% 100%)', + '3': 'linear-gradient(to right, #000 60%, transparent 60% 100%)', + '4': 'linear-gradient(to right, #000 50%, transparent 50% 100%)', +}); + +export const masksCornerCuts = tokens.create('masks-corner-cuts', { + '1': 'polygon(0 8%, 8% 0, 100% 0, 100% 100%, 0 100%)', + '2': 'polygon(0 15%, 15% 0, 100% 0, 100% 100%, 0 100%)', + '3': 'polygon(0 22%, 22% 0, 100% 0, 100% 100%, 0 100%)', + '4': 'polygon(0 30%, 30% 0, 100% 0, 100% 100%, 0 100%)', + '5': 'polygon(0 8%, 8% 0, 92% 0, 100% 8%, 100% 100%, 0 100%)', + '6': 'polygon(0 15%, 15% 0, 85% 0, 100% 15%, 100% 100%, 0 100%)', +}); + +export function useOpenProps(namespace: string) { + return tokens.use(namespace); +} diff --git a/packages/open-props/tsconfig.json b/packages/open-props/tsconfig.json new file mode 100644 index 0000000..98e6d70 --- /dev/null +++ b/packages/open-props/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "bundler", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src"], + "exclude": ["node_modules", "dist", "**/*.test.ts"] +} diff --git a/packages/open-props/tsup.config.ts b/packages/open-props/tsup.config.ts new file mode 100644 index 0000000..08b136d --- /dev/null +++ b/packages/open-props/tsup.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: { index: 'src/index.ts' }, + format: ['esm', 'cjs'], + dts: true, + sourcemap: true, + clean: true, + treeshake: true, +}); diff --git a/packages/props/src/createProps.test.ts b/packages/props/src/createProps.test.ts index 8ad3d96..d5a4c1e 100644 --- a/packages/props/src/createProps.test.ts +++ b/packages/props/src/createProps.test.ts @@ -60,9 +60,7 @@ describe('createProps', () => { const props = createProps('atoms', collection); expect(props({ display: { mobile: 'flex' } })).toBe('atoms-display-mobile-flex'); - expect(props({ display: { desktop: 'block' } })).toBe( - 'atoms-display-desktop-block' - ); + expect(props({ display: { desktop: 'block' } })).toBe('atoms-display-desktop-block'); }); it('handles mixed conditional and direct values', () => { @@ -79,7 +77,7 @@ describe('createProps', () => { const props = createProps('atoms', collection); expect(props({ display: { mobile: 'flex' }, padding: 1 })).toBe( - 'atoms-display-mobile-flex atoms-padding-1' + 'atoms-display-mobile-flex atoms-padding-1', ); }); @@ -153,9 +151,7 @@ describe('createProps', () => { const props = createProps('atoms', layout, spacing); - expect(props({ display: 'flex', padding: 1 })).toBe( - 'atoms-display-flex atoms-padding-1' - ); + expect(props({ display: 'flex', padding: 1 })).toBe('atoms-display-flex atoms-padding-1'); }); it('handles null and undefined values', () => { @@ -168,7 +164,7 @@ describe('createProps', () => { const props = createProps('atoms', collection); - expect(props({ display: 'flex', padding: null as any })).toBe('atoms-display-flex'); - expect(props({ display: undefined as any, padding: 1 })).toBe('atoms-padding-1'); + expect(props({ display: 'flex', padding: null as unknown })).toBe('atoms-display-flex'); + expect(props({ display: undefined as unknown, padding: 1 })).toBe('atoms-padding-1'); }); }); diff --git a/packages/props/src/createProps.ts b/packages/props/src/createProps.ts index d59101f..6df45ba 100644 --- a/packages/props/src/createProps.ts +++ b/packages/props/src/createProps.ts @@ -1,4 +1,10 @@ -import type { PropertyCollection, PropsFunction } from './types.js'; +import type { + PropertyCollection, + PropsFunction, + PropertyDefinitions, + ConditionDefinitions, + ShorthandDefinitions, +} from './types.js'; import { insertRules } from 'typestyles'; import { generateFromCollections } from './generate.js'; import { buildLookupMap, createResolver } from './runtime.js'; @@ -19,10 +25,13 @@ import { buildLookupMap, createResolver } from './runtime.js'; * // Returns: "atoms-display-flex atoms-padding-2 atoms-paddingTop-mobile-3" * ``` */ -export function createProps[]>( - namespace: string, - ...collections: Collections -): PropsFunction { +export function createProps< + Collections extends PropertyCollection< + PropertyDefinitions, + ConditionDefinitions, + ShorthandDefinitions + >[], +>(namespace: string, ...collections: Collections): PropsFunction { // Generate all CSS rules upfront const cssRules = generateFromCollections(namespace, collections); @@ -30,10 +39,7 @@ export function createProps = {} ->( - config: DefinePropertiesConfig -): PropertyCollection { + C extends ConditionDefinitions = ConditionDefinitions, + S extends ShorthandDefinitions

= Record>, +>(config: DefinePropertiesConfig): PropertyCollection { const conditions = (config.conditions || {}) as C; const shorthands = (config.shorthands || {}) as S; const defaultCondition = config.defaultCondition ?? false; diff --git a/packages/props/src/generate.ts b/packages/props/src/generate.ts index afde3eb..875c5be 100644 --- a/packages/props/src/generate.ts +++ b/packages/props/src/generate.ts @@ -4,6 +4,7 @@ import type { PropertyCollection, ConditionDefinition, PropertyValues, + ShorthandDefinitions, } from './types.js'; import { sanitizeValue, toKebabCase } from './utils.js'; @@ -15,7 +16,7 @@ function generateAtomicClass( property: string, valueKey: string, cssValue: string | number, - condition?: ConditionDefinition & { name: string } + condition?: ConditionDefinition & { name: string }, ): { key: string; css: string } { const sanitizedValue = sanitizeValue(valueKey); const className = condition @@ -93,12 +94,12 @@ function getValueEntries(values: PropertyValues): Array<[string, string | number */ export function generateAllAtomicClasses< P extends PropertyDefinitions, - C extends ConditionDefinitions + C extends ConditionDefinitions, >( namespace: string, properties: P, conditions: C, - defaultCondition: keyof C | false + defaultCondition: keyof C | false, ): Array<{ key: string; css: string }> { const rules: Array<{ key: string; css: string }> = []; @@ -116,7 +117,7 @@ export function generateAllAtomicClasses< generateAtomicClass(namespace, property, valueKey, cssValue, { ...condition, name: defaultCondition as string, - }) + }), ); } } @@ -132,7 +133,7 @@ export function generateAllAtomicClasses< generateAtomicClass(namespace, property, valueKey, cssValue, { ...condDef, name: condName, - }) + }), ); } } @@ -146,7 +147,11 @@ export function generateAllAtomicClasses< */ export function generateFromCollections( namespace: string, - collections: PropertyCollection[] + collections: PropertyCollection< + PropertyDefinitions, + ConditionDefinitions, + ShorthandDefinitions + >[], ): Array<{ key: string; css: string }> { const allRules: Array<{ key: string; css: string }> = []; @@ -155,7 +160,7 @@ export function generateFromCollections( namespace, collection.properties, collection.conditions, - collection.defaultCondition + collection.defaultCondition, ); allRules.push(...rules); } diff --git a/packages/props/src/runtime.ts b/packages/props/src/runtime.ts index d961bfe..59459cc 100644 --- a/packages/props/src/runtime.ts +++ b/packages/props/src/runtime.ts @@ -12,10 +12,10 @@ import { sanitizeValue, isConditionalValue } from './utils.js'; export function buildLookupMap< P extends PropertyDefinitions, C extends ConditionDefinitions, - S extends ShorthandDefinitions

+ S extends ShorthandDefinitions

, >( - namespace: string, - collections: PropertyCollection[] + _namespace: string, + collections: PropertyCollection[], ): { propertyMap: Map>; conditionKeys: Set; @@ -51,10 +51,10 @@ export function buildLookupMap< * Expand shorthands in props object. */ export function expandShorthands( - props: Record, - shorthands: Map -): Record { - const expanded: Record = {}; + props: Record, + shorthands: Map, +): Record { + const expanded: Record = {}; for (const [key, value] of Object.entries(props)) { if (shorthands.has(key)) { @@ -78,8 +78,8 @@ export function expandShorthands( function resolveValue( namespace: string, property: string, - value: any, - conditionKeys: Set + value: unknown, + conditionKeys: Set, ): string[] { const classNames: string[] = []; @@ -105,11 +105,11 @@ function resolveValue( */ export function createResolver( namespace: string, - propertyMap: Map>, + _propertyMap: Map>, conditionKeys: Set, - shorthands: Map -): (props: Record) => string { - return (props: Record): string => { + shorthands: Map, +): (props: Record) => string { + return (props: Record): string => { // Expand shorthands const expanded = expandShorthands(props, shorthands); diff --git a/packages/props/src/types.ts b/packages/props/src/types.ts index b08990a..80439b1 100644 --- a/packages/props/src/types.ts +++ b/packages/props/src/types.ts @@ -27,10 +27,7 @@ export type PropertyDefinitions = Record; /** * Shorthand definitions - map shorthand names to arrays of property names. */ -export type ShorthandDefinitions

= Record< - string, - Array ->; +export type ShorthandDefinitions

= Record>; /** * The configuration object passed to defineProperties(). @@ -38,7 +35,7 @@ export type ShorthandDefinitions

= Record< export interface DefinePropertiesConfig< P extends PropertyDefinitions, C extends ConditionDefinitions, - S extends ShorthandDefinitions

+ S extends ShorthandDefinitions

, > { properties: P; conditions?: C; @@ -52,7 +49,7 @@ export interface DefinePropertiesConfig< export interface PropertyCollection< P extends PropertyDefinitions, C extends ConditionDefinitions, - S extends ShorthandDefinitions

+ S extends ShorthandDefinitions

, > { readonly properties: P; readonly conditions: C; @@ -65,9 +62,9 @@ export interface PropertyCollection< */ type ExtractValue = T extends (infer U)[] ? U - : T extends Record - ? keyof T - : never; + : T extends Record + ? keyof T + : never; /** * Create a prop value type that can be a direct value or a conditional object. @@ -84,30 +81,32 @@ type PropValue = export type ExtractProps< P extends PropertyDefinitions, C extends ConditionDefinitions, - S extends ShorthandDefinitions

+ S extends ShorthandDefinitions

, > = { [K in keyof P | keyof S]?: K extends keyof S ? PropValue, C> : K extends keyof P - ? PropValue, C> - : never; + ? PropValue, C> + : never; }; /** * The props function signature. */ -export type PropsFunction[]> = (( +export type PropsFunction< + Collections extends PropertyCollection< + PropertyDefinitions, + ConditionDefinitions, + ShorthandDefinitions + >[], +> = (( props: UnionToIntersection< { - [I in keyof Collections]: Collections[I] extends PropertyCollection< - infer P, - infer C, - infer S - > + [I in keyof Collections]: Collections[I] extends PropertyCollection ? ExtractProps : never; }[number] - > + >, ) => string) & { properties: Set; }; @@ -115,8 +114,8 @@ export type PropsFunction[ /** * Convert a union type to an intersection type. */ -type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ( - k: infer I +type UnionToIntersection = (U extends unknown ? (k: U) => void : never) extends ( + k: infer I, ) => void ? I : never; diff --git a/packages/props/src/utils.ts b/packages/props/src/utils.ts index ab9f881..d3f8038 100644 --- a/packages/props/src/utils.ts +++ b/packages/props/src/utils.ts @@ -23,9 +23,9 @@ export function toKebabCase(str: string): string { * Check if a value is a conditional object (has condition keys). */ export function isConditionalValue( - value: any, - conditionKeys: Set -): value is Record { + value: unknown, + conditionKeys: Set, +): value is Record { if (typeof value !== 'object' || value === null || Array.isArray(value)) { return false; } diff --git a/packages/typestyles/src/hmr.test.ts b/packages/typestyles/src/hmr.test.ts index 876b73d..2756bbe 100644 --- a/packages/typestyles/src/hmr.test.ts +++ b/packages/typestyles/src/hmr.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { invalidatePrefix, invalidateKeys } from './hmr.js'; -import { insertRule, insertRules, flushSync, reset } from './sheet.js'; +import { insertRule, flushSync, reset } from './sheet.js'; describe('invalidatePrefix', () => { beforeEach(() => { diff --git a/packages/typestyles/src/styles.test.ts b/packages/typestyles/src/styles.test.ts index bfd294d..801100b 100644 --- a/packages/typestyles/src/styles.test.ts +++ b/packages/typestyles/src/styles.test.ts @@ -42,7 +42,9 @@ describe('createStyles', () => { disabled: { opacity: 0.5 }, }); + // eslint-disable-next-line no-constant-binary-expression expect(card('base', false && 'active', null, undefined)).toBe('card-base'); + // eslint-disable-next-line no-constant-binary-expression expect(card('base', true && 'active')).toBe('card-base card-active'); }); @@ -152,7 +154,7 @@ describe('compose', () => { const isDisabled = false; expect(composed('root', isActive && 'active', isDisabled && 'disabled')).toBe( - 'base3-root base3-active extra-class' + 'base3-root base3-active extra-class', ); }); diff --git a/packages/typestyles/src/styles.ts b/packages/typestyles/src/styles.ts index 4e74384..fc3387f 100644 --- a/packages/typestyles/src/styles.ts +++ b/packages/typestyles/src/styles.ts @@ -74,7 +74,7 @@ export function createStyles( * ``` */ type AnySelectorFunction = { - (...args: any[]): string; + (...args: unknown[]): string; }; export function compose( @@ -82,7 +82,7 @@ export function compose( ): AnySelectorFunction { const validSelectors = selectors.filter(Boolean) as Array; - return (...args: any[]): string => { + return (...args: unknown[]): string => { const classNames: string[] = []; for (const selector of validSelectors) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index da3cd8e..9f3b990 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -110,6 +110,25 @@ importers: specifier: ^6.0.0 version: 6.4.1(@types/node@25.2.1)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + packages/open-props: + dependencies: + open-props: + specifier: ^1.7.0 + version: 1.7.23 + typestyles: + specifier: workspace:* + version: link:../typestyles + devDependencies: + tsup: + specifier: ^8.0.0 + version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vitest: + specifier: ^3.0.0 + version: 3.2.4(@types/debug@4.1.12)(@types/node@25.2.1)(jiti@2.6.1)(jsdom@25.0.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + packages/props: dependencies: typestyles: @@ -2076,6 +2095,9 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + open-props@1.7.23: + resolution: {integrity: sha512-+xyrJmxV9QUBFbSwPROYhOg/FLXry+uuPr4R+B5EaE4556Oc18/8ZC/fL5A+/lbRSwNvA0Alh+C0KpyFWLmLZg==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -4838,6 +4860,8 @@ snapshots: object-assign@4.1.1: {} + open-props@1.7.23: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4