Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add @openlabs/system module #332

Merged
merged 1 commit into from
May 31, 2024
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
49 changes: 49 additions & 0 deletions packages/system/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "@openlabs/system",
"version": "0.1.0",
"description": "Open UI System primitives",
"publishConfig": {
"access": "public"
},
"author": "Open Labs",
"license": "MIT",
"homepage": "https://github.com/OpenLabs-dev/openui#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/OpenLabs-dev/openui.git"
},
"bugs": {
"url": "https://github.com/OpenLabs-dev/openui/issues"
},
"keywords": [
"ui",
"design system",
"open",
"theme",
"system"
],
"sideEffects": false,
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"./package.json": "./package.json"
},
"scripts": {
"build": "tsup --dts",
"compile": "tsup --dts --watch"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
},
"devDependencies": {
"@openlabs/tsconfig": "workspace:*",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tsup": "^8.0.2",
"typescript": "^5.4.5"
}
}
15 changes: 15 additions & 0 deletions packages/system/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export type {
As,
DOMElement,
DOMElements,
CapitalizedDOMElements,
DOMAttributes,
OmitCommonProps,
RightJoinProps,
MergeWithAs,
InternalForwardRefRenderFunction,
PropsOf,
Merge,
HTMLOpenUIProps,
PropGetter,
} from '@system/types'
11 changes: 11 additions & 0 deletions packages/system/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "@openlabs/tsconfig/base.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@system/types": ["types/index.d.ts"]
}
},
"include": ["."],
"exclude": ["dist", "build", "node_modules"]
}
10 changes: 10 additions & 0 deletions packages/system/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineConfig } from 'tsup'

export default defineConfig({
name: 'system',
entry: ['src/index.ts'],
clean: true,
target: 'es2019',
format: ['cjs', 'esm'],
banner: { js: '"use client";' },
})
69 changes: 69 additions & 0 deletions packages/system/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
export type As<Props = any> = React.ElementType<Props>
export type DOMElements = keyof JSX.IntrinsicElements
export type CapitalizedDOMElements = Capitalize<DOMElements>

export interface DOMElement extends Element, HTMLOrSVGElement {}

interface DataAttributes {
[dataAttr: string]: any
}

export type DOMAttributes<T = DOMElement> = React.AriaAttributes & React.DOMAttributes<T> & DataAttributes & {
id?: string
role?: React.AriaRole
tabIndex?: number
style?: React.CSSProperties
}

export type OmitCommonProps<Target, OmitAdditionalProps extends keyof any = never> = Omit<Target, 'transition' | 'as' | 'color' | OmitAdditionalProps>

export type RightJoinProps<SourceProps extends object = object, OverrideProps extends object = object> = OmitCommonProps<SourceProps, keyof OverrideProps> & OverrideProps

export type MergeWithAs<
ComponentProps extends object,
AsProps extends object,
AdditionalProps extends object = object,
AsComponent extends As = As,
> = (RightJoinProps<ComponentProps, AdditionalProps> | RightJoinProps<AsProps, AdditionalProps>) & {
as?: AsComponent
}

export interface InternalForwardRefRenderFunction<
Component extends As,
Props extends object = object,
OmitKeys extends keyof any = never,
> {
<AsComponent extends As = Component>(
props: MergeWithAs<
React.ComponentPropsWithoutRef<Component>,
Omit<React.ComponentPropsWithoutRef<AsComponent>, OmitKeys>,
Props,
AsComponent
>,
): React.ReactElement | null
readonly $$typeof: symbol
defaultProps?: Partial<Props> | undefined
propTypes?: React.WeakValidationMap<Props> | undefined
displayName?: string | undefined
}

/**
* Extract the props of a React element or component
*/
export type PropsOf<T extends As> = React.ComponentPropsWithoutRef<T> & {
as?: As
}

export type Merge<M, N> = N extends Record<string, unknown> ? M : Omit<M, keyof N> & N

export type HTMLOpenUIProps<T extends As = 'div', OmitKeys extends keyof any = never> = Omit<
PropsOf<T>,
'ref' | 'color' | 'slot' | 'size' | 'defaultChecked' | 'defaultValue' | OmitKeys
> & {
as?: As
}

export type PropGetter<P = Record<string, unknown>, R = DOMAttributes> = (
props?: Merge<DOMAttributes, P>,
ref?: React.Ref<any>,
) => R & React.RefAttributes<any>
2 changes: 1 addition & 1 deletion packages/theme/src/base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { LayoutTheme } from './interfaces/theme'
import type { LayoutTheme } from '@theme/types'

export const defatulTheme: LayoutTheme = {
fontSize: {
Expand Down
2 changes: 1 addition & 1 deletion packages/theme/src/colors/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { BaseColors } from '../interfaces/utils'
import type { BaseColors } from '@theme/types'

export const colors: BaseColors = {
light: {
Expand Down
3 changes: 1 addition & 2 deletions packages/theme/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
import Color from 'color'
import kebabCase from 'lodash.kebabcase'
import mapKeys from 'lodash.mapkeys'
import type { ConfigTheme } from './interfaces/theme'
import type { DefaultThemeType, Resolved } from './interfaces/utils'
import type { ConfigTheme, DefaultThemeType, Resolved } from '@theme/types'
import { flattenThemeObject } from './utils/functions'

const parsedColorsCache: Record<string, number[]> = {}
Expand Down
2 changes: 1 addition & 1 deletion packages/theme/src/create-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import plugin from 'tailwindcss/plugin.js'
import type { DefaultThemeType } from './interfaces/utils'
import type { DefaultThemeType } from '@theme/types'
import type { ConfigThemes } from './tailwindcss'
import { config } from './config'
import { animations, baseStyles, tailwind, utilities } from './theme'
Expand Down
31 changes: 15 additions & 16 deletions packages/theme/src/tailwindcss.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import type plugin from 'tailwindcss/plugin.js'
import type { ConfigTheme, OpenUIPluginConfig } from '@theme/types'
import deepMerge from 'deepmerge'
import get from 'lodash.get'
import omit from 'lodash.omit'
import forEach from 'lodash.foreach'
import type { OpenUIPluginConfig } from './interfaces/config'
import type { ConfigTheme } from './interfaces/theme'
import {
darkTheme,
defatulTheme,
Expand All @@ -27,44 +26,44 @@ export function openui(config: OpenUIPluginConfig = {}): ReturnType<typeof plugi
prefix: defaultPrefix = DEFAULT_PREFIX,
} = config

const userLightColors = get(themeObject, 'light.colors', {})
const userDarkColors = get(themeObject, 'dark.colors', {})
const customLightColors = get(themeObject, 'light.colors', {})
const customDarkColors = get(themeObject, 'dark.colors', {})

const defaultLayoutObj = userLayout && typeof userLayout === 'object'
const mergedLayout = userLayout && typeof userLayout === 'object'
? deepMerge(defatulTheme, userLayout)
: defatulTheme

const baseLayouts = {
const mergedThemeLayouts = {
light: {
...defaultLayoutObj,
...mergedLayout,
...lightTheme,
},
dark: {
...defaultLayoutObj,
...mergedLayout,
...darkTheme,
},
}

const otherThemes = omit(themeObject, ['light', 'dark']) || {}

forEach(otherThemes, ({ extend, colors, layout }, themeName) => {
const baseTheme = extend && isBaseTheme(extend) ? extend : defaultExtendTheme
const defaultExtensionTheme = extend && isBaseTheme(extend) ? extend : defaultExtendTheme

if (colors && typeof colors === 'object')
otherThemes[themeName].colors = deepMerge(semanticColors[baseTheme], colors)
otherThemes[themeName].colors = deepMerge(semanticColors[defaultExtensionTheme], colors)

if (layout && typeof layout === 'object')
otherThemes[themeName].layout = deepMerge(extend ? baseLayouts[extend] : defaultLayoutObj, layout)
otherThemes[themeName].layout = deepMerge(extend ? mergedThemeLayouts[extend] : mergedLayout, layout)
})

const light: ConfigTheme = {
layout: deepMerge(baseLayouts.light, get(themeObject, 'light.layout', {})),
colors: deepMerge(semanticColors.light, userLightColors),
layout: deepMerge(mergedThemeLayouts.light, get(themeObject, 'light.layout', {})),
colors: deepMerge(semanticColors.light, customLightColors),
}

const dark = {
layout: deepMerge(baseLayouts.dark, get(themeObject, 'dark.layout', {})),
colors: deepMerge(semanticColors.dark, userDarkColors),
const dark: ConfigTheme = {
layout: deepMerge(mergedThemeLayouts.dark, get(themeObject, 'dark.layout'), {}),
colors: deepMerge(semanticColors.dark, customDarkColors),
}

const themes = {
Expand Down
7 changes: 7 additions & 0 deletions packages/theme/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
{
"extends": "@openlabs/tsconfig/base.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@theme/types": ["./types/index.d.ts"]
}
},
"include": ["."],
"exclude": ["dist", "build", "node_modules"]
}
2 changes: 1 addition & 1 deletion packages/theme/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { defineConfig } from 'tsup'

export default defineConfig({
name: 'theme',
entryPoints: ['./src/index.ts'],
entry: ['./src/index.ts'],
format: ['cjs', 'esm'],
clean: true,
target: 'es2019',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import type { ConfigThemes } from '../tailwindcss'
import type { LayoutTheme } from './theme'
import type { DefaultThemeType } from './utils'

export interface OpenUIPluginConfig {
/**
* The prefix for the css variables.
* @default "openui"
*/
prefix?: string
/**
* Common layout definitions. These definitions are applied to all themes.
*/
layout?: LayoutTheme
/**
* The theme definitions.
*/
themes?: ConfigThemes
/**
* The default theme to use is light
* @default "light"
*/
defaultTheme?: DefaultThemeType
/**
* The default theme to extend.
* @default "light"
*/
defaultExtendTheme?: DefaultThemeType
}
import type { LayoutTheme } from './theme'
import type { DefaultThemeType } from './utils'
import type { ConfigThemes } from '@/tailwindcss'
export interface OpenUIPluginConfig {
/**
* The prefix for the css variables.
* @default "openui"
*/
prefix?: string
/**
* Common layout definitions. These definitions are applied to all themes.
*/
layout?: LayoutTheme
/**
* The theme definitions.
*/
themes?: ConfigThemes
/**
* The default theme to use is light
* @default "light"
*/
defaultTheme?: DefaultThemeType
/**
* The default theme to extend.
* @default "light"
*/
defaultExtendTheme?: DefaultThemeType
}
14 changes: 14 additions & 0 deletions packages/theme/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export type {
DefaultThemeType,
Color,
Colors,
BaseColors,
BaseUnit,
OpacityValue,
OpacityColor,
Resolved,
} from './utils'

export type { ConfigTheme, LayoutTheme } from './theme'

export type { OpenUIPluginConfig } from './config'
Loading
Loading