@hellboy/ds 0.1.2

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 (137) hide show
  1. package/README.md +111 -0
  2. package/dist/index.css +3699 -0
  3. package/dist/index.css.map +1 -0
  4. package/dist/index.d.mts +1087 -0
  5. package/dist/index.d.ts +1087 -0
  6. package/dist/index.js +3391 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/index.mjs +3287 -0
  9. package/dist/index.mjs.map +1 -0
  10. package/dist/theme.css +55 -0
  11. package/hellboy-ds-0.1.2.tgz +0 -0
  12. package/package.json +42 -0
  13. package/src/components/badge/Badge.tsx +29 -0
  14. package/src/components/badge/index.ts +1 -0
  15. package/src/components/banner/Banner.tsx +48 -0
  16. package/src/components/banner/banner.css +44 -0
  17. package/src/components/banner/index.ts +1 -0
  18. package/src/components/button/button.tsx +127 -0
  19. package/src/components/button/index.ts +1 -0
  20. package/src/components/card/card.tsx +57 -0
  21. package/src/components/card/index.ts +1 -0
  22. package/src/components/checkbox/Checkbox.tsx +98 -0
  23. package/src/components/checkbox/index.ts +1 -0
  24. package/src/components/code-block/code-block.tsx +44 -0
  25. package/src/components/code-block/index.ts +1 -0
  26. package/src/components/color-control/color-control.tsx +322 -0
  27. package/src/components/color-control/index.ts +1 -0
  28. package/src/components/drag-handle/DragHandle.tsx +78 -0
  29. package/src/components/drag-handle/index.ts +1 -0
  30. package/src/components/drawer/drawer.tsx +82 -0
  31. package/src/components/drawer/index.ts +1 -0
  32. package/src/components/floating-bar/floating-bar.tsx +52 -0
  33. package/src/components/floating-bar/index.ts +2 -0
  34. package/src/components/footer/footer.tsx +28 -0
  35. package/src/components/footer/index.ts +1 -0
  36. package/src/components/grid/Grid.tsx +53 -0
  37. package/src/components/grid/index.ts +1 -0
  38. package/src/components/header/header.tsx +57 -0
  39. package/src/components/header/index.ts +1 -0
  40. package/src/components/icons/icons.tsx +44 -0
  41. package/src/components/icons/index.ts +1 -0
  42. package/src/components/index.ts +29 -0
  43. package/src/components/input/DatePicker.tsx +133 -0
  44. package/src/components/input/Input.tsx +220 -0
  45. package/src/components/input/InputDate.tsx +10 -0
  46. package/src/components/input/InputDateTime.tsx +10 -0
  47. package/src/components/input/InputEmail.tsx +10 -0
  48. package/src/components/input/InputField.tsx +137 -0
  49. package/src/components/input/InputNumber.tsx +10 -0
  50. package/src/components/input/InputPassword.tsx +10 -0
  51. package/src/components/input/InputSearch.tsx +10 -0
  52. package/src/components/input/InputTel.tsx +10 -0
  53. package/src/components/input/InputText.tsx +10 -0
  54. package/src/components/input/InputTime.tsx +10 -0
  55. package/src/components/input/InputUrl.tsx +10 -0
  56. package/src/components/input/TimePicker.tsx +151 -0
  57. package/src/components/input/index.ts +11 -0
  58. package/src/components/layout/Layout.tsx +244 -0
  59. package/src/components/layout/index.ts +1 -0
  60. package/src/components/list/List.tsx +159 -0
  61. package/src/components/list/index.ts +1 -0
  62. package/src/components/navbar/MenuCategory.tsx +20 -0
  63. package/src/components/navbar/MenuGroup.tsx +288 -0
  64. package/src/components/navbar/MenuItem.tsx +65 -0
  65. package/src/components/navbar/Navbar.tsx +23 -0
  66. package/src/components/navbar/index.ts +4 -0
  67. package/src/components/page/index.ts +1 -0
  68. package/src/components/page/page.tsx +46 -0
  69. package/src/components/page-index/PageIndex.tsx +275 -0
  70. package/src/components/page-index/index.ts +1 -0
  71. package/src/components/popover/index.ts +1 -0
  72. package/src/components/popover/popover.tsx +199 -0
  73. package/src/components/radio/Radio.tsx +176 -0
  74. package/src/components/radio/index.ts +1 -0
  75. package/src/components/section/index.ts +1 -0
  76. package/src/components/section/section.tsx +66 -0
  77. package/src/components/select/Select.tsx +212 -0
  78. package/src/components/select/index.ts +1 -0
  79. package/src/components/slider/Slider.tsx +267 -0
  80. package/src/components/slider/index.ts +1 -0
  81. package/src/components/switch/index.ts +1 -0
  82. package/src/components/switch/switch.tsx +99 -0
  83. package/src/components/table/Table.tsx +147 -0
  84. package/src/components/table/index.ts +1 -0
  85. package/src/components/theme-control/index.ts +1 -0
  86. package/src/components/theme-control/theme-control.tsx +78 -0
  87. package/src/components/tooltip/index.ts +1 -0
  88. package/src/components/tooltip/tooltip.tsx +207 -0
  89. package/src/contexts/NavbarTooltipContext.tsx +48 -0
  90. package/src/contexts/index.ts +1 -0
  91. package/src/foundations/motion.md +136 -0
  92. package/src/index.ts +40 -0
  93. package/src/style/_shared/field.css +69 -0
  94. package/src/style/components/badge/badge.css +74 -0
  95. package/src/style/components/button/button.css +244 -0
  96. package/src/style/components/card/card.css +69 -0
  97. package/src/style/components/checkbox.css +142 -0
  98. package/src/style/components/code-block/code-block.css +34 -0
  99. package/src/style/components/color-control/color-control.css +126 -0
  100. package/src/style/components/drag-handle/drag-handle.css +68 -0
  101. package/src/style/components/drawer/drawer.css +210 -0
  102. package/src/style/components/floating-bar/floating-bar.css +39 -0
  103. package/src/style/components/footer/footer.css +108 -0
  104. package/src/style/components/grid/grid.css +33 -0
  105. package/src/style/components/header/header.css +44 -0
  106. package/src/style/components/icons/icons.css +44 -0
  107. package/src/style/components/input/input.css +393 -0
  108. package/src/style/components/layout/layout.css +205 -0
  109. package/src/style/components/list/list.css +140 -0
  110. package/src/style/components/navbar/navbar.css +342 -0
  111. package/src/style/components/page/page.css +46 -0
  112. package/src/style/components/page-index/page-index.css +158 -0
  113. package/src/style/components/popover/popover.css +44 -0
  114. package/src/style/components/radio.css +178 -0
  115. package/src/style/components/section/section.css +67 -0
  116. package/src/style/components/select/select.css +143 -0
  117. package/src/style/components/slider/slider.css +159 -0
  118. package/src/style/components/switch/switch.css +267 -0
  119. package/src/style/components/table/table.css +108 -0
  120. package/src/style/components/theme-control/theme-control.css +35 -0
  121. package/src/style/components/tooltip/tooltip.css +52 -0
  122. package/src/style/foundations/global.css +316 -0
  123. package/src/style/foundations/motion.css +164 -0
  124. package/src/style/foundations/spacing.css +51 -0
  125. package/src/style/foundations/typography.css +39 -0
  126. package/src/style/foundations/z-index.css +81 -0
  127. package/src/style/modes/dark.css +146 -0
  128. package/src/style/modes/light.css +147 -0
  129. package/src/style/semantic.css +52 -0
  130. package/src/style/styles.css +51 -0
  131. package/src/style/themes/theme.json +37 -0
  132. package/src/utils/README.md +305 -0
  133. package/src/utils/USER_PREFERENCES.md +558 -0
  134. package/src/utils/theme.ts +127 -0
  135. package/src/utils/user-preferences.ts +577 -0
  136. package/tsconfig.json +25 -0
  137. package/tsup.config.ts +52 -0
package/dist/theme.css ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Theme Configuration (generated from theme.json)
3
+ * Generated during build from src/style/themes/theme.json
4
+ */
5
+
6
+ :root {
7
+ /* Primary Color */
8
+ --primary-hue: 0;
9
+ --primary-saturation: 69%;
10
+ --primary-lightness: 31%;
11
+ --primary-lightness-hover: undefined%;
12
+ --primary-lightness-active: undefined%;
13
+ --primary-lightness-disabled: undefined%;
14
+
15
+ /* Secondary Color */
16
+ --secondary-hue: 16;
17
+ --secondary-saturation: 63%;
18
+ --secondary-lightness: 23%;
19
+ --secondary-lightness-hover: undefined%;
20
+ --secondary-lightness-active: undefined%;
21
+ --secondary-lightness-disabled: undefined%;
22
+
23
+ /* Accent Color */
24
+ --accent-hue: 0;
25
+ --accent-saturation: 89%;
26
+ --accent-lightness: 41%;
27
+ --accent-lightness-hover: undefined%;
28
+ --accent-lightness-active: undefined%;
29
+ --accent-lightness-disabled: undefined%;
30
+
31
+ /* Status Colors */
32
+ --success-hue: 140;
33
+ --success-saturation: 100%;
34
+ --success-lightness: 19%;
35
+ --success-lightness-hover: undefined%;
36
+ --success-lightness-active: undefined%;
37
+
38
+ --warning-hue: 34;
39
+ --warning-saturation: 100%;
40
+ --warning-lightness: 31%;
41
+ --warning-lightness-hover: undefined%;
42
+ --warning-lightness-active: undefined%;
43
+
44
+ --error-hue: 264;
45
+ --error-saturation: 0%;
46
+ --error-lightness: 14%;
47
+ --error-lightness-hover: undefined%;
48
+ --error-lightness-active: undefined%;
49
+
50
+ --info-hue: 261;
51
+ --info-saturation: 69%;
52
+ --info-lightness: 31%;
53
+ --info-lightness-hover: undefined%;
54
+ --info-lightness-active: undefined%;
55
+ }
Binary file
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@hellboy/ds",
3
+ "version": "0.1.2",
4
+ "description": "Hellboy Design System - Core components",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ },
14
+ "./dist/index.css": "./dist/index.css",
15
+ "./dist/theme.css": "./dist/theme.css"
16
+ },
17
+ "scripts": {
18
+ "build": "tsup src/index.ts --dts",
19
+ "dev": "tsup src/index.ts --dts --watch"
20
+ },
21
+ "keywords": [
22
+ "design-system",
23
+ "components",
24
+ "ui"
25
+ ],
26
+ "author": "",
27
+ "license": "MIT",
28
+ "dependencies": {
29
+ "@ariakit/react": "^0.4.0",
30
+ "@iconify/react": "^6.0.2",
31
+ "famicons": "^7.2.3"
32
+ },
33
+ "devDependencies": {
34
+ "@types/react": "^18.2.0",
35
+ "tsup": "^8.5.1",
36
+ "typescript": "^5.3.0"
37
+ },
38
+ "peerDependencies": {
39
+ "react": "^18.0.0",
40
+ "react-dom": "^18.0.0"
41
+ }
42
+ }
@@ -0,0 +1,29 @@
1
+ import * as React from 'react';
2
+ import '../../style/components/badge/badge.css';
3
+
4
+ export type BadgeVariant = 'primary' | 'secondary' | 'tertiary' | 'accent' | 'success' | 'warning' | 'error' | 'info';
5
+ export type BadgeSize = 'sm' | 'md' | 'lg';
6
+
7
+ export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
8
+ variant?: BadgeVariant;
9
+ size?: BadgeSize;
10
+ children: React.ReactNode;
11
+ }
12
+
13
+ export const Badge: React.FC<BadgeProps> = ({
14
+ variant = 'primary',
15
+ size = 'md',
16
+ className = '',
17
+ children,
18
+ ...props
19
+ }) => {
20
+ const classes = ['badge', `badge--${variant}`, `badge--${size}`, className]
21
+ .filter(Boolean)
22
+ .join(' ');
23
+
24
+ return (
25
+ <span className={classes} {...props}>
26
+ {children}
27
+ </span>
28
+ );
29
+ };
@@ -0,0 +1 @@
1
+ export * from './Badge';
@@ -0,0 +1,48 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { Icon } from '../icons';
3
+ import { Button } from '../button';
4
+ import './banner.css';
5
+
6
+ export type BannerType = 'info' | 'warning' | 'error' | 'success';
7
+
8
+ export interface BannerProps {
9
+ type?: BannerType;
10
+ children: ReactNode;
11
+ icon?: string;
12
+ onDismiss?: () => void;
13
+ }
14
+
15
+ export const Banner: React.FC<BannerProps> = ({
16
+ type = 'info',
17
+ children,
18
+ icon,
19
+ onDismiss
20
+ }) => {
21
+ const defaultIcons: Record<BannerType, string> = {
22
+ info: 'information-circle',
23
+ warning: 'warning',
24
+ error: 'close-circle',
25
+ success: 'checkmark-circle'
26
+ };
27
+
28
+ const displayIcon = icon || defaultIcons[type];
29
+
30
+ return (
31
+ <div className={`banner banner--${type}`}>
32
+ <div className="banner__content">
33
+ <Icon name={displayIcon as any} size={32} />
34
+ <div className="banner__message">{children}</div>
35
+ </div>
36
+ {onDismiss && (
37
+ <Button
38
+ variant="ghost"
39
+ size="xs"
40
+ onClick={onDismiss}
41
+ aria-label="Dismiss banner"
42
+ >
43
+ <Icon name="close" size={20} />
44
+ </Button>
45
+ )}
46
+ </div>
47
+ );
48
+ };
@@ -0,0 +1,44 @@
1
+ .banner {
2
+ display: flex;
3
+ align-items: flex-start;
4
+ justify-content: space-between;
5
+ padding: var(--spacing-4);
6
+ border-radius: var(--border-radius-md, 8px);
7
+ margin-bottom: var(--spacing-4);
8
+ font-weight: 500;
9
+ gap: var(--spacing-3);
10
+ }
11
+
12
+ .banner__content {
13
+ display: flex;
14
+ align-items: flex-start;
15
+ gap: var(--spacing-3);
16
+ flex: 1;
17
+ }
18
+
19
+ .banner__message {
20
+ flex: 1;
21
+ line-height: 1.5;
22
+ margin: var(--spacing-1) var(--spacing-1) var(--spacing-1) 0;
23
+ }
24
+
25
+ /* Type variants */
26
+ .banner--info {
27
+ background-color: hsla(var(--info-hue), var(--info-saturation), var(--info-lightness), 1);
28
+ color: hsla(var(--info-hue), 0%, 100%, 1);
29
+ }
30
+
31
+ .banner--warning {
32
+ background-color: hsla(var(--warning-hue), var(--warning-saturation), var(--warning-lightness), 1);
33
+ color: hsla(var(--warning-hue), 0%, 100%, 1);
34
+ }
35
+
36
+ .banner--error {
37
+ background-color: hsla(var(--error-hue), var(--error-saturation), var(--error-lightness), 1);
38
+ color: hsla(var(--error-hue), 0%, 100%, 1);
39
+ }
40
+
41
+ .banner--success {
42
+ background-color: hsla(var(--success-hue), var(--success-saturation), var(--success-lightness), 1);
43
+ color: hsla(var(--success-hue), 0%, 100%, 1);
44
+ }
@@ -0,0 +1 @@
1
+ export * from "./Banner";
@@ -0,0 +1,127 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { Button as AriakitButton, ButtonProps as AriakitButtonProps } from '@ariakit/react';
3
+ import { Icon, IconName } from '../icons';
4
+
5
+ export type ButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'ghost';
6
+ export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';
7
+
8
+ export interface ButtonProps extends Omit<AriakitButtonProps, 'children'> {
9
+ /**
10
+ * Visual variant of the button
11
+ * @default 'primary'
12
+ */
13
+ variant?: ButtonVariant;
14
+
15
+ /**
16
+ * Size of the button
17
+ * @default 'md'
18
+ */
19
+ size?: ButtonSize;
20
+
21
+ /**
22
+ * Button content
23
+ */
24
+ children?: ReactNode;
25
+
26
+ /**
27
+ * Whether the button is in a loading state
28
+ * @default false
29
+ */
30
+ isLoading?: boolean;
31
+
32
+ /**
33
+ * Full width button
34
+ * @default false
35
+ */
36
+ fullWidth?: boolean;
37
+
38
+ /**
39
+ * Icon to display at the start of the button
40
+ */
41
+ startIcon?: IconName;
42
+
43
+ /**
44
+ * Icon to display at the end of the button
45
+ */
46
+ endIcon?: IconName;
47
+
48
+ /**
49
+ * Whether the button should only display an icon (no text)
50
+ * @default false
51
+ */
52
+ iconOnly?: boolean;
53
+
54
+ /**
55
+ * URL to navigate to when button is clicked (makes it work like a link)
56
+ */
57
+ href?: string;
58
+ }
59
+
60
+ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
61
+ (
62
+ {
63
+ variant = 'primary',
64
+ size = 'md',
65
+ children,
66
+ isLoading = false,
67
+ disabled = false,
68
+ fullWidth = false,
69
+ startIcon,
70
+ endIcon,
71
+ iconOnly = false,
72
+ href,
73
+ className,
74
+ onClick,
75
+ ...props
76
+ },
77
+ ref
78
+ ) => {
79
+ const buttonClasses = [
80
+ 'btn',
81
+ `btn--${variant}`,
82
+ `btn--${size}`,
83
+ fullWidth && 'btn--full-width',
84
+ iconOnly && 'btn--icon-only',
85
+ className,
86
+ ]
87
+ .filter(Boolean)
88
+ .join(' ');
89
+
90
+ const iconSize = size === 'xs' ? 14 : size === 'sm' ? 16 : size === 'lg' ? 24 : 20;
91
+
92
+ const buttonContent = (
93
+ <>
94
+ {isLoading && <span className="btn__spinner" />}
95
+ {startIcon && (
96
+ isLoading ? (
97
+ <span className="btn__icon-placeholder" style={{ width: iconSize, height: iconSize }} />
98
+ ) : (
99
+ <Icon name={startIcon} size={iconSize} className="btn__icon" />
100
+ )
101
+ )}
102
+ {!iconOnly && children}
103
+ {endIcon && <Icon name={endIcon} size={iconSize} className="btn__icon" />}
104
+ </>
105
+ );
106
+
107
+ const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
108
+ if (href && !isLoading && !disabled) {
109
+ window.location.href = href;
110
+ }
111
+ onClick?.(e);
112
+ };
113
+
114
+ return (
115
+ <AriakitButton
116
+ ref={ref}
117
+ disabled={disabled || isLoading}
118
+ className={buttonClasses}
119
+ onClick={handleClick}
120
+ {...props}
121
+ >
122
+ {buttonContent}
123
+ </AriakitButton>
124
+ );
125
+ });
126
+
127
+ Button.displayName = 'Button';
@@ -0,0 +1 @@
1
+ export { Button, type ButtonProps, type ButtonVariant, type ButtonSize } from './button';
@@ -0,0 +1,57 @@
1
+ import React, { ReactNode } from 'react';
2
+ import '../../style/components/card/card.css';
3
+
4
+ export type CardVariant = 'default' | 'elevated' | 'outlined';
5
+
6
+ export interface CardProps {
7
+ /**
8
+ * Visual variant of the card
9
+ * @default 'default'
10
+ */
11
+ variant?: CardVariant;
12
+
13
+ /**
14
+ * Card content
15
+ */
16
+ children: ReactNode;
17
+
18
+ /**
19
+ * Additional CSS classes
20
+ */
21
+ className?: string;
22
+
23
+ /**
24
+ * Click handler for interactive cards
25
+ */
26
+ onClick?: () => void;
27
+ }
28
+
29
+ export const Card: React.FC<CardProps> = ({
30
+ variant = 'default',
31
+ children,
32
+ className = '',
33
+ onClick,
34
+ ...props
35
+ }) => {
36
+ const cardClasses = [
37
+ 'card',
38
+ `card--${variant}`,
39
+ onClick && 'card--interactive',
40
+ className,
41
+ ]
42
+ .filter(Boolean)
43
+ .join(' ');
44
+
45
+ const Component = onClick ? 'button' : 'div';
46
+
47
+ return (
48
+ <Component
49
+ className={cardClasses}
50
+ onClick={onClick}
51
+ {...(onClick && { type: 'button' })}
52
+ {...props}
53
+ >
54
+ {children}
55
+ </Component>
56
+ );
57
+ };
@@ -0,0 +1 @@
1
+ export * from './card';
@@ -0,0 +1,98 @@
1
+ import React from 'react';
2
+ import { Checkbox as AriakitCheckbox, CheckboxProps as AriakitCheckboxProps } from '@ariakit/react';
3
+ import { Icon } from '../icons';
4
+
5
+ export type CheckboxSize = 'sm' | 'md' | 'lg';
6
+
7
+ export interface CheckboxProps extends Omit<AriakitCheckboxProps, 'children' | 'size'> {
8
+ /**
9
+ * Size of the checkbox
10
+ * @default 'md'
11
+ */
12
+ size?: CheckboxSize;
13
+
14
+ /**
15
+ * Label text for the checkbox
16
+ */
17
+ label?: React.ReactNode;
18
+
19
+ /**
20
+ * Error message to display below the checkbox
21
+ */
22
+ error?: string;
23
+
24
+ /**
25
+ * Helper text to display below the checkbox
26
+ */
27
+ helperText?: string;
28
+
29
+ /**
30
+ * Whether the checkbox is in an indeterminate state
31
+ * @default false
32
+ */
33
+ indeterminate?: boolean;
34
+ }
35
+
36
+ export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
37
+ (
38
+ {
39
+ size = 'md',
40
+ label,
41
+ error,
42
+ helperText,
43
+ indeterminate = false,
44
+ disabled = false,
45
+ className,
46
+ checked,
47
+ ...props
48
+ },
49
+ ref
50
+ ) => {
51
+ const checkboxClasses = [
52
+ 'checkbox',
53
+ `checkbox--${size}`,
54
+ error && 'checkbox--error',
55
+ disabled && 'checkbox--disabled',
56
+ className,
57
+ ]
58
+ .filter(Boolean)
59
+ .join(' ');
60
+
61
+ const iconSize = size === 'sm' ? 14 : size === 'lg' ? 20 : 16;
62
+
63
+ // Determine checked state for icon display
64
+ const isChecked = checked === true;
65
+ const isIndeterminate = indeterminate && !isChecked;
66
+
67
+ return (
68
+ <div className={checkboxClasses}>
69
+ <label className="checkbox__container">
70
+ <AriakitCheckbox
71
+ ref={ref}
72
+ checked={checked}
73
+ disabled={disabled}
74
+ className="checkbox__input"
75
+ {...props}
76
+ />
77
+ <span className="checkbox__box">
78
+ {isChecked && (
79
+ <Icon name="checkmark-sharp" size={iconSize} className="checkbox__icon" />
80
+ )}
81
+ {isIndeterminate && (
82
+ <Icon name="minus" size={iconSize} className="checkbox__icon" />
83
+ )}
84
+ </span>
85
+ {label && <span className="checkbox__label">{label}</span>}
86
+ </label>
87
+ {(error || helperText) && (
88
+ <div className="checkbox__feedback">
89
+ {error && <span className="checkbox__error-text">{error}</span>}
90
+ {!error && helperText && <span className="checkbox__helper-text">{helperText}</span>}
91
+ </div>
92
+ )}
93
+ </div>
94
+ );
95
+ }
96
+ );
97
+
98
+ Checkbox.displayName = 'Checkbox';
@@ -0,0 +1 @@
1
+ export * from './Checkbox';
@@ -0,0 +1,44 @@
1
+ import React, { ReactNode } from 'react';
2
+
3
+ export type CodeBlockVariant = 'block' | 'inline';
4
+
5
+ export interface CodeBlockProps {
6
+ /**
7
+ * Code content
8
+ */
9
+ children: ReactNode;
10
+
11
+ /**
12
+ * Variant of the code block
13
+ * @default 'block'
14
+ */
15
+ variant?: CodeBlockVariant;
16
+
17
+ /**
18
+ * Custom class name
19
+ */
20
+ className?: string;
21
+ }
22
+
23
+ /**
24
+ * CodeBlock component for displaying code snippets
25
+ */
26
+ export const CodeBlock: React.FC<CodeBlockProps> = ({ children, variant = 'block', className }) => {
27
+ const classes = [
28
+ 'code-block',
29
+ variant === 'inline' && 'code-block--inline',
30
+ className,
31
+ ]
32
+ .filter(Boolean)
33
+ .join(' ');
34
+
35
+ if (variant === 'inline') {
36
+ return <code className={classes}>{children}</code>;
37
+ }
38
+
39
+ return (
40
+ <pre className={classes}>
41
+ <code>{children}</code>
42
+ </pre>
43
+ );
44
+ };
@@ -0,0 +1 @@
1
+ export { CodeBlock, type CodeBlockProps, type CodeBlockVariant } from './code-block';