@xjur-ui/react 1.0.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.
Files changed (70) hide show
  1. package/.turbo/turbo-build.log +57 -0
  2. package/dist/components/resources/icons.d.ts +4 -0
  3. package/dist/components/resources/icons.js +133 -0
  4. package/dist/components/resources/logo/horizontal.d.ts +12 -0
  5. package/dist/components/resources/logo/horizontal.js +107 -0
  6. package/dist/components/resources/logo/icon.d.ts +12 -0
  7. package/dist/components/resources/logo/icon.js +79 -0
  8. package/dist/components/resources/logo/index.d.ts +4 -0
  9. package/dist/components/resources/logo/index.js +291 -0
  10. package/dist/components/resources/logo/vertical.d.ts +12 -0
  11. package/dist/components/resources/logo/vertical.js +107 -0
  12. package/dist/components/ui/accordion.d.ts +5 -0
  13. package/dist/components/ui/accordion.js +8 -0
  14. package/dist/components/ui/button.d.ts +16 -0
  15. package/dist/components/ui/button.js +95 -0
  16. package/dist/components/ui/icon.d.ts +12 -0
  17. package/dist/components/ui/icon.js +158 -0
  18. package/dist/components/ui/index.d.ts +17 -0
  19. package/dist/components/ui/index.js +788 -0
  20. package/dist/components/ui/input/content.d.ts +9 -0
  21. package/dist/components/ui/input/content.js +183 -0
  22. package/dist/components/ui/input/index.d.ts +12 -0
  23. package/dist/components/ui/input/index.js +335 -0
  24. package/dist/components/ui/input/label.d.ts +12 -0
  25. package/dist/components/ui/input/label.js +165 -0
  26. package/dist/components/ui/input/message.d.ts +10 -0
  27. package/dist/components/ui/input/message.js +128 -0
  28. package/dist/components/ui/input/root.d.ts +18 -0
  29. package/dist/components/ui/input/root.js +163 -0
  30. package/dist/components/ui/input/slot.d.ts +10 -0
  31. package/dist/components/ui/input/slot.js +20 -0
  32. package/dist/components/ui/input/text.d.ts +10 -0
  33. package/dist/components/ui/input/text.js +195 -0
  34. package/dist/components/ui/logo.d.ts +10 -0
  35. package/dist/components/ui/logo.js +324 -0
  36. package/dist/components/ui/otp-input.d.ts +13 -0
  37. package/dist/components/ui/otp-input.js +47 -0
  38. package/dist/components/ui/typography.d.ts +17 -0
  39. package/dist/components/ui/typography.js +78 -0
  40. package/dist/index.css +770 -0
  41. package/dist/index.d.ts +17 -0
  42. package/dist/index.js +788 -0
  43. package/eslint.config.js +3 -0
  44. package/package.json +41 -0
  45. package/postcss.config.js +5 -0
  46. package/prettier.config.js +7 -0
  47. package/src/components/resources/icons.ts +131 -0
  48. package/src/components/resources/logo/horizontal.tsx +70 -0
  49. package/src/components/resources/logo/icon.tsx +54 -0
  50. package/src/components/resources/logo/index.ts +3 -0
  51. package/src/components/resources/logo/vertical.tsx +70 -0
  52. package/src/components/ui/accordion.tsx +3 -0
  53. package/src/components/ui/button.tsx +105 -0
  54. package/src/components/ui/icon.tsx +29 -0
  55. package/src/components/ui/index.ts +13 -0
  56. package/src/components/ui/input/content.tsx +59 -0
  57. package/src/components/ui/input/index.ts +6 -0
  58. package/src/components/ui/input/label.tsx +41 -0
  59. package/src/components/ui/input/message.tsx +37 -0
  60. package/src/components/ui/input/root.tsx +57 -0
  61. package/src/components/ui/input/slot.tsx +21 -0
  62. package/src/components/ui/input/text.tsx +69 -0
  63. package/src/components/ui/logo.tsx +39 -0
  64. package/src/components/ui/otp-input.tsx +45 -0
  65. package/src/components/ui/typography.tsx +85 -0
  66. package/src/index.css +2 -0
  67. package/src/index.ts +2 -0
  68. package/src/types.d.ts +4 -0
  69. package/tsconfig.json +4 -0
  70. package/tsup.config.ts +12 -0
@@ -0,0 +1,37 @@
1
+ import { memo } from 'react'
2
+ import { cx } from '@xjur-ui/util'
3
+ import { Typography, type TypographyProps } from '../typography'
4
+ import { useInput } from './root'
5
+
6
+ export type InputMessageProps = TypographyProps
7
+
8
+ export const InputMessage = memo(
9
+ ({
10
+ children,
11
+ className,
12
+ weight = 'normal',
13
+ variant = 'body',
14
+ size = 'sm-1x',
15
+ ...props
16
+ }: InputMessageProps) => {
17
+ const { errorMessage } = useInput()
18
+
19
+ return (
20
+ <Typography
21
+ className={cx(
22
+ 'text-neutral-dark data-[error=true]:text-danger-idle',
23
+ className
24
+ )}
25
+ data-error={!!errorMessage}
26
+ size={size}
27
+ variant={variant}
28
+ weight={weight}
29
+ {...props}
30
+ >
31
+ {children}
32
+ </Typography>
33
+ )
34
+ }
35
+ )
36
+
37
+ InputMessage.displayName = 'InputMessage'
@@ -0,0 +1,57 @@
1
+ import { type ComponentProps, createContext, use } from 'react'
2
+ import { cx } from '@xjur-ui/util'
3
+ import { InputMessage } from './message'
4
+
5
+ export type InputRoot = {
6
+ size?: 'md' | 'lg'
7
+ rounded?: boolean
8
+ errorMessage?: string
9
+ disabled?: boolean
10
+ }
11
+
12
+ export const InputRootContext = createContext({} as InputRoot)
13
+
14
+ export function useInput() {
15
+ const context = use(InputRootContext)
16
+
17
+ if (!context) {
18
+ throw new Error(
19
+ 'useInput must be called within <Input.Root> or <Select.Root>'
20
+ )
21
+ }
22
+
23
+ return context
24
+ }
25
+
26
+ export type InputRootProps = ComponentProps<'div'> & {
27
+ children: ComponentProps<'div'>['children']
28
+ } & InputRoot
29
+
30
+ export function InputRoot({
31
+ children,
32
+ className,
33
+ errorMessage,
34
+ size = 'lg',
35
+ rounded = false,
36
+ disabled,
37
+ ...props
38
+ }: InputRootProps) {
39
+ return (
40
+ <InputRootContext.Provider
41
+ value={{ errorMessage, disabled, size, rounded }}
42
+ >
43
+ <div
44
+ {...props}
45
+ className={cx(
46
+ 'group gap-small relative flex flex-col data-[disabled=true]:opacity-60',
47
+ className
48
+ )}
49
+ data-disabled={disabled}
50
+ >
51
+ {children}
52
+
53
+ {errorMessage && <InputMessage>{errorMessage}</InputMessage>}
54
+ </div>
55
+ </InputRootContext.Provider>
56
+ )
57
+ }
@@ -0,0 +1,21 @@
1
+ import { type ComponentProps, memo } from 'react'
2
+ import { cx } from '@xjur-ui/util'
3
+
4
+ export type InputSlotProps = ComponentProps<'label'> & {
5
+ children: ComponentProps<'label'>['children']
6
+ }
7
+
8
+ export const InputSlot = memo(
9
+ ({ children, className, ...props }: InputSlotProps) => {
10
+ return (
11
+ <label
12
+ {...props}
13
+ className={cx('flex items-center justify-center', className)}
14
+ >
15
+ {children}
16
+ </label>
17
+ )
18
+ }
19
+ )
20
+
21
+ InputSlot.displayName = 'InputSlot'
@@ -0,0 +1,69 @@
1
+ import { InputMask, type MaskOptions } from '@react-input/mask'
2
+ import { type ComponentProps, useCallback, useEffect, useRef } from 'react'
3
+ import { cx } from '@xjur-ui/util'
4
+ import { useInput } from './root'
5
+
6
+ export type InputTextProps = ComponentProps<'input'> & { mask?: MaskOptions }
7
+
8
+ export function InputText({
9
+ className,
10
+ value,
11
+ mask,
12
+ ...props
13
+ }: InputTextProps) {
14
+ const { errorMessage } = useInput()
15
+ const inputRef = useRef<HTMLInputElement>(null)
16
+ const InputComponent = mask ? InputMask : 'input'
17
+
18
+ const onCheckInputFilled = useCallback(
19
+ ({ shouldUnfill = false }: { shouldUnfill: boolean }) => {
20
+ if (inputRef.current) {
21
+ if (shouldUnfill) inputRef.current.dataset.filled = 'false'
22
+ else {
23
+ const hasNotErrorAndHasValue =
24
+ !errorMessage && !!inputRef.current.value
25
+ inputRef.current.dataset.filled = String(hasNotErrorAndHasValue)
26
+ }
27
+ }
28
+ },
29
+ [errorMessage]
30
+ )
31
+
32
+ function setRef(ref: HTMLInputElement) {
33
+ inputRef.current = ref
34
+
35
+ if (typeof props.ref === 'function') {
36
+ props.ref(ref)
37
+ }
38
+ }
39
+
40
+ useEffect(() => {
41
+ onCheckInputFilled({ shouldUnfill: false })
42
+ }, [onCheckInputFilled])
43
+
44
+ return (
45
+ <InputComponent
46
+ {...props}
47
+ {...(mask && { ...mask })}
48
+ className={cx(
49
+ 'h-full w-full bg-transparent',
50
+ 'border-hidden outline-hidden',
51
+ 'placeholder:text-placeholder-neutral font-normal',
52
+ 'text-neutral-dark text-size-body-md overflow-hidden text-ellipsis',
53
+ className
54
+ )}
55
+ data-filled={!!value && !errorMessage}
56
+ readOnly={props.readOnly !== undefined && props.readOnly}
57
+ ref={setRef}
58
+ value={value}
59
+ onBlur={event => {
60
+ props.onBlur?.(event)
61
+ onCheckInputFilled({ shouldUnfill: false })
62
+ }}
63
+ onFocus={event => {
64
+ props.onFocus?.(event)
65
+ onCheckInputFilled({ shouldUnfill: true })
66
+ }}
67
+ />
68
+ )
69
+ }
@@ -0,0 +1,39 @@
1
+ import { memo } from 'react'
2
+ import { Horizontal, Vertical, Icon } from '../resources/logo'
3
+
4
+ export interface LogoProps {
5
+ mode?: 'horizontal' | 'vertical' | 'icon'
6
+ variant?: 'colorful' | 'orange' | 'purple' | 'white' | 'gray'
7
+ }
8
+
9
+ export const Logo = memo(
10
+ ({ mode = 'horizontal', variant = 'colorful' }: LogoProps) => {
11
+ const colorToHex = {
12
+ orange: '#D68600',
13
+ purple: '#66127D',
14
+ white: '#FFFFFF',
15
+ gray: '#6B7280'
16
+ }
17
+
18
+ switch (mode) {
19
+ case 'icon':
20
+ if (variant === 'colorful') {
21
+ return <Icon.Colorful />
22
+ }
23
+ return <Icon.Solid color={colorToHex[variant]} />
24
+ case 'vertical':
25
+ if (variant === 'colorful') {
26
+ return <Vertical.Colorful />
27
+ }
28
+ return <Vertical.Solid color={colorToHex[variant]} />
29
+ case 'horizontal':
30
+ default:
31
+ if (variant === 'colorful') {
32
+ return <Horizontal.Colorful />
33
+ }
34
+ return <Horizontal.Solid color={colorToHex[variant]} />
35
+ }
36
+ }
37
+ )
38
+
39
+ Logo.displayName = 'Logo'
@@ -0,0 +1,45 @@
1
+ import * as OTPPasswordField from '@radix-ui/react-one-time-password-field'
2
+ import { cx } from '@xjur-ui/util'
3
+
4
+ function Root({
5
+ children,
6
+ className,
7
+ ...props
8
+ }: OTPPasswordField.OneTimePasswordFieldProps) {
9
+ return (
10
+ <OTPPasswordField.Root
11
+ className={cx(className, 'group gap-small flex items-center')}
12
+ {...props}
13
+ >
14
+ {children}
15
+ </OTPPasswordField.Root>
16
+ )
17
+ }
18
+
19
+ function Input({
20
+ className,
21
+ ...props
22
+ }: OTPPasswordField.OneTimePasswordFieldInputProps) {
23
+ return (
24
+ <OTPPasswordField.Input
25
+ className={cx(
26
+ className,
27
+ 'text-neutral-dark h-large-6x bg-layer-2-hover rounded-small-1x w-full text-center outline-0',
28
+ 'focus-within:border-primary-idle focus-within:shadow-focus-primary focus-within:border'
29
+ )}
30
+ {...props}
31
+ />
32
+ )
33
+ }
34
+
35
+ function HiddenInput({
36
+ ...props
37
+ }: OTPPasswordField.OneTimePasswordFieldHiddenInputProps) {
38
+ return <OTPPasswordField.HiddenInput {...props} />
39
+ }
40
+
41
+ export const OTPInput = {
42
+ Root,
43
+ Input,
44
+ HiddenInput
45
+ }
@@ -0,0 +1,85 @@
1
+ import { Slot } from '@radix-ui/react-slot'
2
+ import { cva, type ClassVariantProps } from '@xjur-ui/util'
3
+ import { memo, type ComponentProps } from 'react'
4
+
5
+ const typographyVariants = cva('', {
6
+ variants: {
7
+ variant: {
8
+ body: '',
9
+ label: '',
10
+ title: '',
11
+ headline: ''
12
+ },
13
+ size: {
14
+ 'sm-2x': '',
15
+ 'sm-1x': '',
16
+ sm: '',
17
+ md: '',
18
+ lg: ''
19
+ },
20
+ weight: {
21
+ thin: 'font-thin',
22
+ extraLight: 'font-extralight',
23
+ light: 'font-light',
24
+ normal: 'font-normal',
25
+ medium: 'font-medium',
26
+ semibold: 'font-semibold',
27
+ bold: 'font-bold',
28
+ extraBold: 'font-extrabold',
29
+ black: 'font-black'
30
+ }
31
+ },
32
+ compoundVariants: [
33
+ { variant: 'body', size: 'sm-1x', class: 'text-size-body-sm-1x' },
34
+ { variant: 'body', size: 'sm', class: 'text-size-body-sm' },
35
+ { variant: 'body', size: 'md', class: 'text-size-body-md' },
36
+ { variant: 'body', size: 'lg', class: 'text-size-body-lg' },
37
+
38
+ { variant: 'label', size: 'sm-2x', class: 'text-size-label-sm-2x' },
39
+ { variant: 'label', size: 'sm-1x', class: 'text-size-label-sm-1x' },
40
+ { variant: 'label', size: 'sm', class: 'text-size-label-sm' },
41
+ { variant: 'label', size: 'md', class: 'text-size-label-md' },
42
+ { variant: 'label', size: 'lg', class: 'text-size-label-lg' },
43
+
44
+ { variant: 'title', size: 'sm', class: 'text-size-title-sm' },
45
+ { variant: 'title', size: 'md', class: 'text-size-title-md' },
46
+ { variant: 'title', size: 'lg', class: 'text-size-title-lg' },
47
+
48
+ { variant: 'headline', size: 'sm', class: 'text-size-headline-sm' },
49
+ { variant: 'headline', size: 'md', class: 'text-size-headline-md' },
50
+ { variant: 'headline', size: 'lg', class: 'text-size-headline-lg' }
51
+ ],
52
+ defaultVariants: {
53
+ variant: 'body',
54
+ size: 'md',
55
+ weight: 'normal'
56
+ }
57
+ })
58
+
59
+ export interface TypographyProps
60
+ extends ComponentProps<'base'>,
61
+ ClassVariantProps<typeof typographyVariants> {
62
+ asChild?: boolean
63
+ }
64
+
65
+ export const Typography = memo(
66
+ ({
67
+ variant,
68
+ size,
69
+ weight,
70
+ asChild,
71
+ className,
72
+ ...props
73
+ }: TypographyProps) => {
74
+ const Component = asChild ? Slot : 'span'
75
+
76
+ return (
77
+ <Component
78
+ className={typographyVariants({ variant, size, weight, className })}
79
+ {...props}
80
+ />
81
+ )
82
+ }
83
+ )
84
+
85
+ Typography.displayName = 'Typography'
package/src/index.css ADDED
@@ -0,0 +1,2 @@
1
+ @import "tailwindcss";
2
+ @import "@xjur-ui/styles/theme.css";
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ import './index.css'
2
+ export * from './components/ui'
package/src/types.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ declare module '*.css' {
2
+ const content: Record<string, string>
3
+ export default content
4
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "@xjur-ui/typescript-config/react",
3
+ "include": ["src"]
4
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from 'tsup'
2
+
3
+ export default defineConfig({
4
+ // all js and ts
5
+ entry: ['src/index.ts', 'src/components/**/*.ts', 'src/components/**/*.tsx'],
6
+ format: ['esm'],
7
+ outDir: 'dist',
8
+ external: ['react', 'react-dom'],
9
+ dts: true,
10
+ splitting: false,
11
+ clean: true
12
+ })