@mdxui/terminal 2.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 (191) hide show
  1. package/README.md +571 -0
  2. package/dist/ansi-css-Sk5mWtdK.d.ts +119 -0
  3. package/dist/ansi-css-V6JIHGsM.d.ts +119 -0
  4. package/dist/ansi-css-_3eSEU9d.d.ts +119 -0
  5. package/dist/chunk-3EFDH7PK.js +5235 -0
  6. package/dist/chunk-3RG5ZIWI.js +10 -0
  7. package/dist/chunk-3X5IR6WE.js +884 -0
  8. package/dist/chunk-4FV5ZDCE.js +5236 -0
  9. package/dist/chunk-4OVMSF2J.js +243 -0
  10. package/dist/chunk-63FEETIS.js +4048 -0
  11. package/dist/chunk-B43KP7XJ.js +884 -0
  12. package/dist/chunk-BMTJXWUV.js +655 -0
  13. package/dist/chunk-C3SVH4N7.js +882 -0
  14. package/dist/chunk-EVWR7Y47.js +874 -0
  15. package/dist/chunk-F6A5VWUC.js +1285 -0
  16. package/dist/chunk-FD7KW7GE.js +882 -0
  17. package/dist/chunk-GBQ6UD6I.js +655 -0
  18. package/dist/chunk-GMDD3M6U.js +5227 -0
  19. package/dist/chunk-JBHRXOXM.js +1058 -0
  20. package/dist/chunk-JFOO3EYO.js +1182 -0
  21. package/dist/chunk-JQ5H3WXL.js +1291 -0
  22. package/dist/chunk-JQD5NASE.js +234 -0
  23. package/dist/chunk-KRHJP5R7.js +592 -0
  24. package/dist/chunk-KWF6WVJE.js +962 -0
  25. package/dist/chunk-LHYQVN3H.js +1038 -0
  26. package/dist/chunk-M3TLQLGC.js +1032 -0
  27. package/dist/chunk-MVW4Q5OP.js +240 -0
  28. package/dist/chunk-NXCZSWLU.js +1294 -0
  29. package/dist/chunk-O25TNRO6.js +607 -0
  30. package/dist/chunk-PNECDA2I.js +884 -0
  31. package/dist/chunk-QIHWRLJR.js +962 -0
  32. package/dist/chunk-QW5YMQ7K.js +882 -0
  33. package/dist/chunk-R5U7XKVJ.js +16 -0
  34. package/dist/chunk-RP2MVQLR.js +962 -0
  35. package/dist/chunk-TP6RXGXA.js +1087 -0
  36. package/dist/chunk-TQQSTITZ.js +655 -0
  37. package/dist/chunk-X24GWXQV.js +1281 -0
  38. package/dist/components/index.d.ts +802 -0
  39. package/dist/components/index.js +149 -0
  40. package/dist/data/index.d.ts +2554 -0
  41. package/dist/data/index.js +51 -0
  42. package/dist/forms/index.d.ts +1596 -0
  43. package/dist/forms/index.js +464 -0
  44. package/dist/index-CQRFZntR.d.ts +867 -0
  45. package/dist/index.d.ts +579 -0
  46. package/dist/index.js +786 -0
  47. package/dist/interactive-D0JkWosD.d.ts +217 -0
  48. package/dist/keyboard/index.d.ts +2 -0
  49. package/dist/keyboard/index.js +43 -0
  50. package/dist/renderers/index.d.ts +546 -0
  51. package/dist/renderers/index.js +2157 -0
  52. package/dist/storybook/index.d.ts +396 -0
  53. package/dist/storybook/index.js +641 -0
  54. package/dist/theme/index.d.ts +1339 -0
  55. package/dist/theme/index.js +123 -0
  56. package/dist/types-Bxu5PAgA.d.ts +710 -0
  57. package/dist/types-CIlop5Ji.d.ts +701 -0
  58. package/dist/types-Ca8p_p5X.d.ts +710 -0
  59. package/package.json +90 -0
  60. package/src/__tests__/components/data/card.test.ts +458 -0
  61. package/src/__tests__/components/data/list.test.ts +473 -0
  62. package/src/__tests__/components/data/metrics.test.ts +541 -0
  63. package/src/__tests__/components/data/table.test.ts +448 -0
  64. package/src/__tests__/components/input/field.test.ts +555 -0
  65. package/src/__tests__/components/input/form.test.ts +870 -0
  66. package/src/__tests__/components/input/search.test.ts +1238 -0
  67. package/src/__tests__/components/input/select.test.ts +658 -0
  68. package/src/__tests__/components/navigation/breadcrumb.test.ts +923 -0
  69. package/src/__tests__/components/navigation/command-palette.test.ts +1095 -0
  70. package/src/__tests__/components/navigation/sidebar.test.ts +1018 -0
  71. package/src/__tests__/components/navigation/tabs.test.ts +995 -0
  72. package/src/__tests__/components.test.tsx +1197 -0
  73. package/src/__tests__/core/compiler.test.ts +986 -0
  74. package/src/__tests__/core/parser.test.ts +785 -0
  75. package/src/__tests__/core/tier-switcher.test.ts +1103 -0
  76. package/src/__tests__/core/types.test.ts +1398 -0
  77. package/src/__tests__/data/collections.test.ts +1337 -0
  78. package/src/__tests__/data/db.test.ts +1265 -0
  79. package/src/__tests__/data/reactive.test.ts +1010 -0
  80. package/src/__tests__/data/sync.test.ts +1614 -0
  81. package/src/__tests__/errors.test.ts +660 -0
  82. package/src/__tests__/forms/integration.test.ts +444 -0
  83. package/src/__tests__/integration.test.ts +905 -0
  84. package/src/__tests__/keyboard.test.ts +1791 -0
  85. package/src/__tests__/renderer.test.ts +489 -0
  86. package/src/__tests__/renderers/ansi-css.test.ts +948 -0
  87. package/src/__tests__/renderers/ansi.test.ts +1366 -0
  88. package/src/__tests__/renderers/ascii.test.ts +1360 -0
  89. package/src/__tests__/renderers/interactive.test.ts +2353 -0
  90. package/src/__tests__/renderers/markdown.test.ts +1483 -0
  91. package/src/__tests__/renderers/text.test.ts +1369 -0
  92. package/src/__tests__/renderers/unicode.test.ts +1307 -0
  93. package/src/__tests__/theme.test.ts +639 -0
  94. package/src/__tests__/utils/assertions.ts +685 -0
  95. package/src/__tests__/utils/index.ts +115 -0
  96. package/src/__tests__/utils/test-renderer.ts +381 -0
  97. package/src/__tests__/utils/utils.test.ts +560 -0
  98. package/src/components/containers/card.ts +56 -0
  99. package/src/components/containers/dialog.ts +53 -0
  100. package/src/components/containers/index.ts +9 -0
  101. package/src/components/containers/panel.ts +59 -0
  102. package/src/components/feedback/badge.ts +40 -0
  103. package/src/components/feedback/index.ts +8 -0
  104. package/src/components/feedback/spinner.ts +23 -0
  105. package/src/components/helpers.ts +81 -0
  106. package/src/components/index.ts +153 -0
  107. package/src/components/layout/breadcrumb.ts +31 -0
  108. package/src/components/layout/index.ts +10 -0
  109. package/src/components/layout/list.ts +29 -0
  110. package/src/components/layout/sidebar.ts +79 -0
  111. package/src/components/layout/table.ts +62 -0
  112. package/src/components/primitives/box.ts +95 -0
  113. package/src/components/primitives/button.ts +54 -0
  114. package/src/components/primitives/index.ts +11 -0
  115. package/src/components/primitives/input.ts +88 -0
  116. package/src/components/primitives/select.ts +97 -0
  117. package/src/components/primitives/text.ts +60 -0
  118. package/src/components/render.ts +155 -0
  119. package/src/components/templates/app.ts +43 -0
  120. package/src/components/templates/index.ts +8 -0
  121. package/src/components/templates/site.ts +54 -0
  122. package/src/components/types.ts +777 -0
  123. package/src/core/compiler.ts +718 -0
  124. package/src/core/parser.ts +127 -0
  125. package/src/core/tier-switcher.ts +607 -0
  126. package/src/core/types.ts +672 -0
  127. package/src/data/collection.ts +316 -0
  128. package/src/data/collections.ts +50 -0
  129. package/src/data/context.tsx +174 -0
  130. package/src/data/db.ts +127 -0
  131. package/src/data/hooks.ts +532 -0
  132. package/src/data/index.ts +138 -0
  133. package/src/data/reactive.ts +1225 -0
  134. package/src/data/saas-collections.ts +375 -0
  135. package/src/data/sync.ts +1213 -0
  136. package/src/data/types.ts +660 -0
  137. package/src/forms/converters.ts +512 -0
  138. package/src/forms/index.ts +133 -0
  139. package/src/forms/schemas.ts +403 -0
  140. package/src/forms/types.ts +476 -0
  141. package/src/index.ts +542 -0
  142. package/src/keyboard/focus.ts +748 -0
  143. package/src/keyboard/index.ts +96 -0
  144. package/src/keyboard/integration.ts +371 -0
  145. package/src/keyboard/manager.ts +377 -0
  146. package/src/keyboard/presets.ts +90 -0
  147. package/src/renderers/ansi-css.ts +576 -0
  148. package/src/renderers/ansi.ts +802 -0
  149. package/src/renderers/ascii.ts +680 -0
  150. package/src/renderers/breadcrumb.ts +480 -0
  151. package/src/renderers/command-palette.ts +802 -0
  152. package/src/renderers/components/field.ts +210 -0
  153. package/src/renderers/components/form.ts +327 -0
  154. package/src/renderers/components/index.ts +21 -0
  155. package/src/renderers/components/search.ts +449 -0
  156. package/src/renderers/components/select.ts +222 -0
  157. package/src/renderers/index.ts +101 -0
  158. package/src/renderers/interactive/component-handlers.ts +622 -0
  159. package/src/renderers/interactive/cursor-manager.ts +147 -0
  160. package/src/renderers/interactive/focus-manager.ts +279 -0
  161. package/src/renderers/interactive/index.ts +661 -0
  162. package/src/renderers/interactive/input-handler.ts +164 -0
  163. package/src/renderers/interactive/keyboard-handler.ts +212 -0
  164. package/src/renderers/interactive/mouse-handler.ts +167 -0
  165. package/src/renderers/interactive/state-manager.ts +109 -0
  166. package/src/renderers/interactive/types.ts +338 -0
  167. package/src/renderers/interactive-string.ts +299 -0
  168. package/src/renderers/interactive.ts +59 -0
  169. package/src/renderers/markdown.ts +950 -0
  170. package/src/renderers/sidebar.ts +549 -0
  171. package/src/renderers/tabs.ts +682 -0
  172. package/src/renderers/text.ts +791 -0
  173. package/src/renderers/unicode.ts +917 -0
  174. package/src/renderers/utils.ts +942 -0
  175. package/src/router/adapters.ts +383 -0
  176. package/src/router/types.ts +140 -0
  177. package/src/router/utils.ts +452 -0
  178. package/src/schemas.ts +205 -0
  179. package/src/storybook/index.ts +91 -0
  180. package/src/storybook/interactive-decorator.tsx +659 -0
  181. package/src/storybook/keyboard-simulator.ts +501 -0
  182. package/src/theme/ansi-codes.ts +80 -0
  183. package/src/theme/box-drawing.ts +132 -0
  184. package/src/theme/color-convert.ts +254 -0
  185. package/src/theme/color-support.ts +321 -0
  186. package/src/theme/index.ts +134 -0
  187. package/src/theme/strip-ansi.ts +50 -0
  188. package/src/theme/tailwind-map.ts +469 -0
  189. package/src/theme/text-styles.ts +206 -0
  190. package/src/theme/theme-system.ts +568 -0
  191. package/src/types.ts +103 -0
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @mdxui/terminal/components/containers/panel
3
+ *
4
+ * Panel component for terminal rendering.
5
+ */
6
+
7
+ import React, { type ReactElement } from 'react'
8
+ import { ANSI, boxChars } from '../../theme'
9
+ import type { PanelProps, RenderContext } from '../types'
10
+ import { extractChildren } from '../helpers'
11
+
12
+ export function renderPanel(props: PanelProps, context: RenderContext): string[] {
13
+ const { children, title, border = 'single', collapsed, padding = 0 } = props
14
+
15
+ // If collapsed, show just the title
16
+ if (collapsed) {
17
+ return [ANSI.dim + '\u25B6 ' + ANSI.reset + ANSI.bold + (title || 'Panel') + ANSI.reset]
18
+ }
19
+
20
+ const lines: string[] = []
21
+ const chars = border === 'double' ? boxChars.double :
22
+ border === 'rounded' ? boxChars.rounded :
23
+ boxChars.single
24
+ const panelWidth = context.width
25
+
26
+ // Top border with title
27
+ if (title && border !== 'none') {
28
+ const titleText = ` ${title} `
29
+ const remainingWidth = panelWidth - titleText.length - 2
30
+ const leftBorder = Math.floor(remainingWidth / 2)
31
+ const rightBorder = remainingWidth - leftBorder
32
+ lines.push(chars.topLeft + chars.horizontal.repeat(leftBorder) + ANSI.bold + titleText + ANSI.reset + chars.horizontal.repeat(rightBorder) + chars.topRight)
33
+ } else if (border !== 'none') {
34
+ lines.push(chars.topLeft + chars.horizontal.repeat(panelWidth - 2) + chars.topRight)
35
+ }
36
+
37
+ // Content
38
+ const content = extractChildren(children)
39
+ const contentLines = content.split('\n')
40
+ const paddingStr = ' '.repeat(padding)
41
+ for (const line of contentLines) {
42
+ if (border !== 'none') {
43
+ lines.push(chars.vertical + paddingStr + line.padEnd(panelWidth - 2 - padding * 2) + paddingStr + chars.vertical)
44
+ } else {
45
+ lines.push(paddingStr + line)
46
+ }
47
+ }
48
+
49
+ // Bottom border
50
+ if (border !== 'none') {
51
+ lines.push(chars.bottomLeft + chars.horizontal.repeat(panelWidth - 2) + chars.bottomRight)
52
+ }
53
+
54
+ return lines
55
+ }
56
+
57
+ export function Panel(props: PanelProps): ReactElement {
58
+ return React.createElement('panel', props)
59
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @mdxui/terminal/components/feedback/badge
3
+ *
4
+ * Badge component for terminal rendering.
5
+ */
6
+
7
+ import React, { type ReactElement } from 'react'
8
+ import { ANSI } from '../../theme'
9
+ import type { BadgeProps, RenderContext } from '../types'
10
+ import { extractChildren } from '../helpers'
11
+
12
+ export function renderBadge(props: BadgeProps, _context: RenderContext): string[] {
13
+ const { children, variant = 'default' } = props
14
+ const text = extractChildren(children)
15
+
16
+ // Color based on variant
17
+ let color: string
18
+ switch (variant) {
19
+ case 'success':
20
+ color = '\x1b[32m' // green
21
+ break
22
+ case 'warning':
23
+ color = '\x1b[33m' // yellow
24
+ break
25
+ case 'error':
26
+ color = '\x1b[31m' // red
27
+ break
28
+ case 'info':
29
+ color = '\x1b[34m' // blue
30
+ break
31
+ default:
32
+ color = ANSI.dim
33
+ }
34
+
35
+ return [color + '[' + text + ']' + ANSI.reset]
36
+ }
37
+
38
+ export function Badge(props: BadgeProps): ReactElement {
39
+ return React.createElement('badge', props)
40
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @mdxui/terminal/components/feedback
3
+ *
4
+ * Feedback terminal components.
5
+ */
6
+
7
+ export { renderBadge, Badge } from './badge'
8
+ export { renderSpinner, Spinner, spinnerFrames } from './spinner'
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @mdxui/terminal/components/feedback/spinner
3
+ *
4
+ * Spinner component for terminal rendering.
5
+ */
6
+
7
+ import React, { type ReactElement } from 'react'
8
+ import { ANSI } from '../../theme'
9
+ import type { SpinnerProps, RenderContext } from '../types'
10
+
11
+ export const spinnerFrames = ['\u280B', '\u2819', '\u2839', '\u2838', '\u283C', '\u2834', '\u2826', '\u2827', '\u2807', '\u280F']
12
+
13
+ export function renderSpinner(props: SpinnerProps, _context: RenderContext): string[] {
14
+ const { label } = props
15
+ // For static rendering, show first frame. In real TUI, this would animate.
16
+ const frame = spinnerFrames[0]
17
+ const text = label ? `${frame} ${label}` : frame
18
+ return [ANSI.cyan + text + ANSI.reset]
19
+ }
20
+
21
+ export function Spinner(props: SpinnerProps): ReactElement {
22
+ return React.createElement('spinner', props)
23
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @mdxui/terminal/components/helpers
3
+ *
4
+ * Helper functions for terminal component rendering.
5
+ */
6
+
7
+ import { type ReactNode, isValidElement } from 'react'
8
+ import { ANSI, colors, visibleLength as themeVisibleLength } from '../theme'
9
+
10
+ // ============================================================================
11
+ // ANSI Color Helpers (using theme module)
12
+ // ============================================================================
13
+
14
+ /**
15
+ * Color map combining basic ANSI colors with semantic theme colors.
16
+ * Re-exports from theme module for backward compatibility.
17
+ */
18
+ export const colorMap: Record<string, string> = {
19
+ // Basic colors (from ANSI)
20
+ black: ANSI.black,
21
+ red: ANSI.red,
22
+ green: ANSI.green,
23
+ yellow: ANSI.yellow,
24
+ blue: ANSI.blue,
25
+ magenta: ANSI.magenta,
26
+ cyan: ANSI.cyan,
27
+ white: ANSI.white,
28
+ // Semantic colors (from theme)
29
+ error: colors.error,
30
+ success: colors.success,
31
+ warning: colors.warning,
32
+ info: colors.info,
33
+ primary: colors.primary,
34
+ secondary: colors.secondary,
35
+ muted: colors.muted,
36
+ }
37
+
38
+ /**
39
+ * Background color map using ANSI constants.
40
+ */
41
+ export const bgColorMap: Record<string, string> = {
42
+ black: ANSI.bgBlack,
43
+ red: ANSI.bgRed,
44
+ green: ANSI.bgGreen,
45
+ yellow: ANSI.bgYellow,
46
+ blue: ANSI.bgBlue,
47
+ magenta: ANSI.bgMagenta,
48
+ cyan: ANSI.bgCyan,
49
+ white: ANSI.bgWhite,
50
+ }
51
+
52
+ export function getColorCode(color: string): string {
53
+ return colorMap[color] || ANSI.white
54
+ }
55
+
56
+ export function getBgColorCode(color: string): string {
57
+ return bgColorMap[color] || ''
58
+ }
59
+
60
+ // ============================================================================
61
+ // Content Extraction Helpers
62
+ // ============================================================================
63
+
64
+ export function extractChildren(children: ReactNode): string {
65
+ if (typeof children === 'string') return children
66
+ if (typeof children === 'number') return String(children)
67
+ if (Array.isArray(children)) {
68
+ return children.map(extractChildren).join('')
69
+ }
70
+ if (isValidElement(children)) {
71
+ const props = children.props as Record<string, unknown>
72
+ return extractChildren(props.children as ReactNode)
73
+ }
74
+ return ''
75
+ }
76
+
77
+ /**
78
+ * Calculate visible length of text (excluding ANSI codes).
79
+ * Re-exported from theme module for backward compatibility.
80
+ */
81
+ export const visibleLength = themeVisibleLength
@@ -0,0 +1,153 @@
1
+ /**
2
+ * @mdxui/terminal/components
3
+ *
4
+ * MDXUI primitives mapped to OpenTUI components.
5
+ * These maintain the same props API as @mdxui/primitives.
6
+ */
7
+
8
+ // ============================================================================
9
+ // Types and Type Guards
10
+ // ============================================================================
11
+
12
+ export type {
13
+ // Render context
14
+ RenderContext,
15
+ TerminalComponentType,
16
+ // Primitive component props
17
+ BoxProps,
18
+ TextProps,
19
+ InputProps,
20
+ SelectOption,
21
+ SelectProps,
22
+ ButtonProps,
23
+ // Container component props
24
+ PanelProps,
25
+ CardProps,
26
+ DialogProps,
27
+ // Layout component props
28
+ TerminalSidebarLayoutProps,
29
+ SidebarItemProps,
30
+ BreadcrumbProps,
31
+ ListProps,
32
+ TableColumn,
33
+ TableProps,
34
+ // Feedback component props
35
+ BadgeProps,
36
+ SpinnerProps,
37
+ // mdxui common types
38
+ NavItem,
39
+ ActionConfig,
40
+ ActionProp,
41
+ ActionsProps,
42
+ FooterLinkGroup,
43
+ SocialLink,
44
+ FeatureItem,
45
+ PricingTier,
46
+ FAQItem,
47
+ DashboardMetric,
48
+ SettingsSection,
49
+ AppHeaderUser,
50
+ BreadcrumbItem,
51
+ // Site component props (mdxui SiteComponents interface)
52
+ SiteProps,
53
+ HeaderProps,
54
+ FooterProps,
55
+ HeroProps,
56
+ FeaturesProps,
57
+ PricingProps,
58
+ FAQProps,
59
+ LandingPageProps,
60
+ PageProps,
61
+ // App component props (mdxui AppComponents interface)
62
+ AppProps,
63
+ ShellProps,
64
+ SidebarProps,
65
+ AppHeaderProps,
66
+ DashboardProps,
67
+ SettingsProps,
68
+ } from './types'
69
+
70
+ export {
71
+ COMPONENT_TYPES,
72
+ isTerminalComponentType,
73
+ isPropsObject,
74
+ isBoxProps,
75
+ isTextProps,
76
+ isTableProps,
77
+ isInputProps,
78
+ isSelectProps,
79
+ isSidebarProps,
80
+ isSidebarItemProps,
81
+ isBreadcrumbProps,
82
+ isBadgeProps,
83
+ isDialogProps,
84
+ isSpinnerProps,
85
+ isButtonProps,
86
+ isPanelProps,
87
+ isListProps,
88
+ isCardProps,
89
+ } from './types'
90
+
91
+ // ============================================================================
92
+ // Helpers
93
+ // ============================================================================
94
+
95
+ export {
96
+ colorMap,
97
+ bgColorMap,
98
+ getColorCode,
99
+ getBgColorCode,
100
+ extractChildren,
101
+ } from './helpers'
102
+
103
+ // ============================================================================
104
+ // Render Functions
105
+ // ============================================================================
106
+
107
+ export { renderComponent, renderElement } from './render'
108
+
109
+ // ============================================================================
110
+ // Primitive Components
111
+ // ============================================================================
112
+
113
+ export { renderBox, Box } from './primitives/box'
114
+ export { renderText, Text } from './primitives/text'
115
+ export { renderInput, Input } from './primitives/input'
116
+ export { renderSelect, Select } from './primitives/select'
117
+ export { renderButton, Button } from './primitives/button'
118
+
119
+ // ============================================================================
120
+ // Container Components
121
+ // ============================================================================
122
+
123
+ export { renderPanel, Panel } from './containers/panel'
124
+ export { renderCard, Card } from './containers/card'
125
+ export { renderDialog, Dialog } from './containers/dialog'
126
+
127
+ // ============================================================================
128
+ // Layout Components
129
+ // ============================================================================
130
+
131
+ export { renderSidebar, renderSidebarItem, SidebarLayout, SidebarItem } from './layout/sidebar'
132
+ export { renderBreadcrumb, Breadcrumb } from './layout/breadcrumb'
133
+ export { renderList, List } from './layout/list'
134
+ export { renderTable, Table } from './layout/table'
135
+
136
+ // ============================================================================
137
+ // Feedback Components
138
+ // ============================================================================
139
+
140
+ export { renderBadge, Badge } from './feedback/badge'
141
+ export { renderSpinner, Spinner, spinnerFrames } from './feedback/spinner'
142
+
143
+ // ============================================================================
144
+ // Site Template Components (mdxui SiteComponents interface)
145
+ // ============================================================================
146
+
147
+ export { Site, Header, Footer, Hero, Features, Pricing, FAQ, LandingPage, Page } from './templates/site'
148
+
149
+ // ============================================================================
150
+ // App Template Components (mdxui AppComponents interface)
151
+ // ============================================================================
152
+
153
+ export { App, Shell, Sidebar, AppHeader, Dashboard, Settings } from './templates/app'
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @mdxui/terminal/components/layout/breadcrumb
3
+ *
4
+ * Breadcrumb component for terminal rendering.
5
+ */
6
+
7
+ import React, { type ReactElement } from 'react'
8
+ import { ANSI } from '../../theme'
9
+ import type { BreadcrumbProps, RenderContext } from '../types'
10
+
11
+ export function renderBreadcrumb(props: BreadcrumbProps, _context: RenderContext): string[] {
12
+ const { items, separator = '/' } = props
13
+
14
+ const parts: string[] = []
15
+ items.forEach((item, idx) => {
16
+ const isLast = idx === items.length - 1
17
+ if (isLast) {
18
+ // Current item - bold
19
+ parts.push(ANSI.bold + item.label + ANSI.reset)
20
+ } else {
21
+ // Previous items - dim
22
+ parts.push(ANSI.dim + item.label + ANSI.reset)
23
+ }
24
+ })
25
+
26
+ return [parts.join(` ${separator} `)]
27
+ }
28
+
29
+ export function Breadcrumb(props: BreadcrumbProps): ReactElement {
30
+ return React.createElement('breadcrumb', props)
31
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @mdxui/terminal/components/layout
3
+ *
4
+ * Layout terminal components.
5
+ */
6
+
7
+ export { renderSidebar, renderSidebarItem, SidebarLayout, SidebarItem } from './sidebar'
8
+ export { renderBreadcrumb, Breadcrumb } from './breadcrumb'
9
+ export { renderList, List } from './list'
10
+ export { renderTable, Table } from './table'
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @mdxui/terminal/components/layout/list
3
+ *
4
+ * List component for terminal rendering.
5
+ */
6
+
7
+ import React, { type ReactElement, type ReactNode } from 'react'
8
+ import { ANSI } from '../../theme'
9
+ import type { ListProps, RenderContext } from '../types'
10
+ import { extractChildren } from '../helpers'
11
+
12
+ export function renderList(props: ListProps, _context: RenderContext): string[] {
13
+ const { items, selectedIndex, bullet = '\u2022', numbered = false } = props
14
+
15
+ return items.map((item, idx) => {
16
+ const text = typeof item === 'string' ? item : extractChildren(item as ReactNode)
17
+ const prefix = numbered ? `${idx + 1}. ` : `${bullet} `
18
+ const isSelected = selectedIndex === idx
19
+
20
+ if (isSelected) {
21
+ return ANSI.cyan + '\x1b[44m' + prefix + text + ANSI.reset
22
+ }
23
+ return prefix + text
24
+ })
25
+ }
26
+
27
+ export function List(props: ListProps): ReactElement {
28
+ return React.createElement('list', props)
29
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * @mdxui/terminal/components/layout/sidebar
3
+ *
4
+ * Internal sidebar layout components for terminal rendering.
5
+ * These are primitive layout components, distinct from mdxui Sidebar.
6
+ */
7
+
8
+ import React, { type ReactElement, Children, isValidElement } from 'react'
9
+ import { ANSI } from '../../theme'
10
+ import type { TerminalSidebarLayoutProps, SidebarItemProps, RenderContext } from '../types'
11
+
12
+ export function renderSidebarItem(props: SidebarItemProps & { _collapsed?: boolean }, _context: RenderContext): string[] {
13
+ const { label, icon, active, _collapsed } = props
14
+
15
+ if (_collapsed) {
16
+ // Only show icon
17
+ return [icon || '']
18
+ }
19
+
20
+ let line = ''
21
+
22
+ // Add active indicator
23
+ if (active) {
24
+ line = '\u25B6 '
25
+ }
26
+
27
+ // Add icon
28
+ if (icon) {
29
+ line += icon + ' '
30
+ }
31
+
32
+ // Add label
33
+ line += label
34
+
35
+ // Apply active styling
36
+ if (active) {
37
+ line = '\x1b[44m' + line + ANSI.reset
38
+ }
39
+
40
+ return [line]
41
+ }
42
+
43
+ export function renderSidebar(props: TerminalSidebarLayoutProps, context: RenderContext): string[] {
44
+ const { children, width = 20, collapsed } = props
45
+ const lines: string[] = []
46
+
47
+ // Render children (SidebarItems)
48
+ const childArray = Children.toArray(children)
49
+ for (const child of childArray) {
50
+ if (isValidElement(child)) {
51
+ const childProps = child.props as SidebarItemProps
52
+ // Pass collapsed state to child
53
+ const modifiedProps = { ...childProps, _collapsed: collapsed }
54
+ const childLines = renderSidebarItem(modifiedProps as SidebarItemProps & { _collapsed?: boolean }, { ...context, width })
55
+ lines.push(...childLines)
56
+ }
57
+ }
58
+
59
+ // Ensure width constraint
60
+ return lines.map(line => {
61
+ const stripped = line.replace(/\x1b\[[\d;]*m/g, '')
62
+ if (stripped.length > width) {
63
+ return line.slice(0, width)
64
+ }
65
+ return line
66
+ })
67
+ }
68
+
69
+ /**
70
+ * SidebarLayout - primitive sidebar layout component for terminal rendering.
71
+ * Use mdxui Sidebar (from templates/app) for mdxui-compatible interface.
72
+ */
73
+ export function SidebarLayout(props: TerminalSidebarLayoutProps): ReactElement {
74
+ return React.createElement('sidebar', props)
75
+ }
76
+
77
+ export function SidebarItem(props: SidebarItemProps): ReactElement {
78
+ return React.createElement('sidebar-item', props)
79
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @mdxui/terminal/components/layout/table
3
+ *
4
+ * Table component for terminal rendering.
5
+ */
6
+
7
+ import React, { type ReactElement } from 'react'
8
+ import { ANSI } from '../../theme'
9
+ import type { TableProps, RenderContext } from '../types'
10
+
11
+ export function renderTable<T>(props: TableProps<T>, _context: RenderContext): string[] {
12
+ const { data, columns, selectedIndex } = props
13
+ const lines: string[] = []
14
+
15
+ // Calculate column widths
16
+ const colWidths = columns.map((col) => {
17
+ if (col.width) return col.width
18
+ let maxWidth = col.header.length
19
+ for (const row of data) {
20
+ const value = String((row as Record<string, unknown>)[col.key as string] ?? '')
21
+ maxWidth = Math.max(maxWidth, value.length)
22
+ }
23
+ return maxWidth + 2 // padding
24
+ })
25
+
26
+ // Render header
27
+ const headerParts = columns.map((col, idx) => {
28
+ const width = colWidths[idx]
29
+ return col.header.padEnd(width)
30
+ })
31
+ lines.push('\u2502' + headerParts.join('\u2502') + '\u2502')
32
+
33
+ // Header separator
34
+ const separatorParts = colWidths.map(w => '\u2500'.repeat(w))
35
+ lines.push('\u251C' + separatorParts.join('\u253C') + '\u2524')
36
+
37
+ // Render rows
38
+ data.forEach((row, rowIndex) => {
39
+ const rowParts = columns.map((col, idx) => {
40
+ const value = String((row as Record<string, unknown>)[col.key as string] ?? '')
41
+ const width = colWidths[idx]
42
+ if (col.align === 'right') {
43
+ return value.padStart(width)
44
+ }
45
+ return value.padEnd(width)
46
+ })
47
+ let rowLine = '\u2502' + rowParts.join('\u2502') + '\u2502'
48
+
49
+ // Highlight selected row
50
+ if (selectedIndex === rowIndex) {
51
+ rowLine = '\x1b[44m' + rowLine + ANSI.reset
52
+ }
53
+
54
+ lines.push(rowLine)
55
+ })
56
+
57
+ return lines
58
+ }
59
+
60
+ export function Table<T>(props: TableProps<T>): ReactElement {
61
+ return React.createElement('table', props as unknown as Record<string, unknown>)
62
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * @mdxui/terminal/components/primitives/box
3
+ *
4
+ * Box component for terminal rendering.
5
+ */
6
+
7
+ import React, { type ReactElement, isValidElement } from 'react'
8
+ import { ANSI, boxChars } from '../../theme'
9
+ import type { BoxProps, RenderContext } from '../types'
10
+ import { extractChildren, getBgColorCode } from '../helpers'
11
+
12
+ // Forward declaration for circular dependency
13
+ let renderElementFn: ((element: ReactElement, context: RenderContext) => string[]) | null = null
14
+
15
+ export function setRenderElement(fn: (element: ReactElement, context: RenderContext) => string[]): void {
16
+ renderElementFn = fn
17
+ }
18
+
19
+ export function renderBox(props: BoxProps, context: RenderContext): string[] {
20
+ const { children, border = 'none', padding = 0, width, height, bg } = props
21
+ const boxWidth = typeof width === 'number' ? width : context.width
22
+ const boxHeight = typeof height === 'number' ? height : undefined
23
+
24
+ // Get child content
25
+ let childLines: string[] = []
26
+ if (children) {
27
+ if (isValidElement(children) && renderElementFn) {
28
+ childLines = renderElementFn(children, { ...context, width: boxWidth - (border !== 'none' ? 2 : 0) - padding * 2, parentWidth: boxWidth })
29
+ } else {
30
+ const text = extractChildren(children)
31
+ if (text) childLines = [text]
32
+ }
33
+ }
34
+
35
+ // Apply padding to content
36
+ if (padding > 0) {
37
+ childLines = childLines.map(line => ' '.repeat(padding) + line + ' '.repeat(padding))
38
+ }
39
+
40
+ // Calculate content width
41
+ const contentWidth = border !== 'none' ? boxWidth - 2 : boxWidth
42
+
43
+ // If no border
44
+ if (border === 'none') {
45
+ let result = childLines.length > 0 ? childLines : ['']
46
+ // Handle height
47
+ if (boxHeight) {
48
+ while (result.length < boxHeight) {
49
+ result.push('')
50
+ }
51
+ result = result.slice(0, boxHeight)
52
+ }
53
+ // Apply background color
54
+ if (bg) {
55
+ const bgCode = getBgColorCode(bg)
56
+ result = result.map(line => bgCode + line.padEnd(boxWidth) + ANSI.reset)
57
+ }
58
+ return result
59
+ }
60
+
61
+ // Get box characters
62
+ const chars = boxChars[border] || boxChars.single
63
+
64
+ // Build box with border
65
+ const lines: string[] = []
66
+
67
+ // Top border
68
+ lines.push(chars.topLeft + chars.horizontal.repeat(contentWidth) + chars.topRight)
69
+
70
+ // Content lines
71
+ const targetHeight = boxHeight ? boxHeight - 2 : childLines.length
72
+
73
+ for (let i = 0; i < targetHeight; i++) {
74
+ const content = i < childLines.length ? childLines[i] : ''
75
+ // Strip ANSI for length calculation
76
+ const stripped = content.replace(/\x1b\[[\d;]*m/g, '')
77
+ const paddedContent = content + ' '.repeat(Math.max(0, contentWidth - stripped.length))
78
+ lines.push(chars.vertical + paddedContent + chars.vertical)
79
+ }
80
+
81
+ // Bottom border
82
+ lines.push(chars.bottomLeft + chars.horizontal.repeat(contentWidth) + chars.bottomRight)
83
+
84
+ // Apply background color
85
+ if (bg) {
86
+ const bgCode = getBgColorCode(bg)
87
+ return lines.map(line => bgCode + line + ANSI.reset)
88
+ }
89
+
90
+ return lines
91
+ }
92
+
93
+ export function Box(props: BoxProps): ReactElement {
94
+ return React.createElement('box', props)
95
+ }