@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,54 @@
1
+ /**
2
+ * @mdxui/terminal/components/primitives/button
3
+ *
4
+ * Button component for terminal rendering.
5
+ */
6
+
7
+ import React, { type ReactElement } from 'react'
8
+ import { ANSI } from '../../theme'
9
+ import type { ButtonProps, RenderContext } from '../types'
10
+ import { extractChildren } from '../helpers'
11
+
12
+ export function renderButton(props: ButtonProps, _context: RenderContext): string[] {
13
+ const { children, hotkey, disabled, focused, variant = 'primary' } = props
14
+ const text = extractChildren(children)
15
+
16
+ let style = ''
17
+ let bgColor = ''
18
+
19
+ // Apply variant styling
20
+ switch (variant) {
21
+ case 'primary':
22
+ bgColor = '\x1b[44m' // blue bg
23
+ style = ANSI.bold
24
+ break
25
+ case 'secondary':
26
+ bgColor = '\x1b[100m' // gray bg
27
+ break
28
+ case 'destructive':
29
+ bgColor = '\x1b[41m' // red bg
30
+ style = ANSI.bold
31
+ break
32
+ }
33
+
34
+ // Build button text
35
+ let buttonText = ` ${text} `
36
+ if (hotkey) {
37
+ buttonText += `[${hotkey}]`
38
+ }
39
+
40
+ // Apply styling
41
+ if (disabled) {
42
+ return [ANSI.dim + `[ ${text} ]` + ANSI.reset]
43
+ }
44
+
45
+ if (focused) {
46
+ return [bgColor + style + '\x1b[37m' + buttonText + ANSI.reset]
47
+ }
48
+
49
+ return [bgColor + style + buttonText + ANSI.reset]
50
+ }
51
+
52
+ export function Button(props: ButtonProps): ReactElement {
53
+ return React.createElement('button', props)
54
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @mdxui/terminal/components/primitives
3
+ *
4
+ * Primitive terminal components.
5
+ */
6
+
7
+ export { renderBox, Box, setRenderElement } from './box'
8
+ export { renderText, Text } from './text'
9
+ export { renderInput, Input } from './input'
10
+ export { renderSelect, Select } from './select'
11
+ export { renderButton, Button } from './button'
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @mdxui/terminal/components/primitives/input
3
+ *
4
+ * Input component for terminal rendering.
5
+ */
6
+
7
+ import React, { type ReactElement } from 'react'
8
+ import { ANSI } from '../../theme'
9
+ import type { InputProps, RenderContext } from '../types'
10
+ import { visibleLength } from '../helpers'
11
+
12
+ export function renderInput(props: InputProps, context: RenderContext): string[] {
13
+ const {
14
+ value = '',
15
+ placeholder = '',
16
+ label,
17
+ disabled,
18
+ focused = false,
19
+ type,
20
+ cursorPosition,
21
+ width,
22
+ } = props
23
+ const lines: string[] = []
24
+
25
+ // Render label
26
+ if (label) {
27
+ lines.push(label)
28
+ }
29
+
30
+ // Determine display value (mask for password, show placeholder when empty)
31
+ let displayValue: string
32
+ if (type === 'password' && value) {
33
+ displayValue = '*'.repeat(value.length)
34
+ } else if (value) {
35
+ displayValue = value
36
+ } else {
37
+ displayValue = ''
38
+ }
39
+
40
+ // Calculate input field width
41
+ const inputWidth = width || context.width || 20
42
+
43
+ // Calculate effective cursor position
44
+ const effectiveCursorPosition = cursorPosition !== undefined
45
+ ? Math.min(cursorPosition, displayValue.length)
46
+ : displayValue.length
47
+
48
+ // Build the rendered string
49
+ let rendered: string
50
+
51
+ if (disabled) {
52
+ // Disabled state: dim text, no cursor
53
+ const content = displayValue || placeholder
54
+ rendered = ANSI.dim + content + ANSI.reset
55
+ } else if (focused) {
56
+ if (displayValue.length === 0) {
57
+ // Empty value when focused: show cursor at start
58
+ rendered = ANSI.inverse + ' ' + ANSI.reset
59
+ } else {
60
+ // Show cursor at position using inverse video
61
+ const before = displayValue.slice(0, effectiveCursorPosition)
62
+ const cursorChar = displayValue[effectiveCursorPosition] || ' '
63
+ const after = displayValue.slice(effectiveCursorPosition + 1)
64
+ rendered = ANSI.underline + before + ANSI.reset + ANSI.inverse + cursorChar + ANSI.reset + ANSI.underline + after + ANSI.reset
65
+ }
66
+ } else {
67
+ // Unfocused state
68
+ if (displayValue.length === 0 && placeholder) {
69
+ // Show placeholder when empty and unfocused
70
+ rendered = ANSI.dim + placeholder + ANSI.reset
71
+ } else {
72
+ rendered = displayValue
73
+ }
74
+ }
75
+
76
+ // Pad to width (accounting for ANSI codes)
77
+ const visible = visibleLength(rendered)
78
+ const padding = ' '.repeat(Math.max(0, inputWidth - visible))
79
+ rendered = rendered + padding
80
+
81
+ lines.push(rendered)
82
+
83
+ return lines
84
+ }
85
+
86
+ export function Input(props: InputProps): ReactElement {
87
+ return React.createElement('input', props)
88
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * @mdxui/terminal/components/primitives/select
3
+ *
4
+ * Select component for terminal rendering.
5
+ */
6
+
7
+ import React, { type ReactElement } from 'react'
8
+ import { ANSI } from '../../theme'
9
+ import type { SelectProps, RenderContext } from '../types'
10
+
11
+ export function renderSelect<T>(props: SelectProps<T>, _context: RenderContext): string[] {
12
+ const {
13
+ options,
14
+ value,
15
+ label,
16
+ focused = false,
17
+ highlightedIndex = 0,
18
+ maxVisible = 5,
19
+ } = props
20
+ const lines: string[] = []
21
+
22
+ // Render label
23
+ if (label) {
24
+ lines.push(label)
25
+ }
26
+
27
+ // Find current selection
28
+ const selectedIndex = options.findIndex(opt => opt.value === value)
29
+ const selected = selectedIndex >= 0 ? options[selectedIndex] : null
30
+
31
+ if (focused) {
32
+ // Calculate visible range based on highlighted index
33
+ let startIdx = 0
34
+ let endIdx = options.length
35
+
36
+ if (options.length > maxVisible) {
37
+ // Center the highlighted option when possible
38
+ const halfVisible = Math.floor(maxVisible / 2)
39
+ startIdx = Math.max(0, highlightedIndex - halfVisible)
40
+ endIdx = Math.min(options.length, startIdx + maxVisible)
41
+
42
+ // Adjust start if we're near the end
43
+ if (endIdx - startIdx < maxVisible) {
44
+ startIdx = Math.max(0, endIdx - maxVisible)
45
+ }
46
+ }
47
+
48
+ // Show scroll indicator at top if needed
49
+ if (startIdx > 0) {
50
+ lines.push(ANSI.dim + ' \u25B2 more' + ANSI.reset)
51
+ }
52
+
53
+ // Render visible options
54
+ for (let idx = startIdx; idx < endIdx; idx++) {
55
+ const opt = options[idx]
56
+ const isSelected = opt.value === value
57
+ const isHighlighted = idx === highlightedIndex
58
+
59
+ // Prefix: selection marker (filled for selected, empty for unselected)
60
+ const prefix = isSelected ? '\u25CF ' : '\u25CB '
61
+
62
+ let line: string
63
+
64
+ if (opt.disabled) {
65
+ // Disabled option: dim with strikethrough indicator
66
+ line = ANSI.dim + prefix + opt.label + ANSI.reset
67
+ } else if (isHighlighted) {
68
+ // Highlighted option: inverse video (highest priority)
69
+ line = ANSI.inverse + prefix + opt.label + ANSI.reset
70
+ } else if (isSelected) {
71
+ // Selected but not highlighted: bold
72
+ line = ANSI.bold + prefix + opt.label + ANSI.reset
73
+ } else {
74
+ // Normal option: dim
75
+ line = ANSI.dim + prefix + opt.label + ANSI.reset
76
+ }
77
+
78
+ lines.push(line)
79
+ }
80
+
81
+ // Show scroll indicator at bottom if needed
82
+ if (endIdx < options.length) {
83
+ lines.push(ANSI.dim + ' \u25BC more' + ANSI.reset)
84
+ }
85
+ } else {
86
+ // Unfocused: show only selected value with dropdown indicator
87
+ const selectedLabel = selected ? selected.label : ''
88
+ const prefix = selected ? '\u25CF ' : '\u25CB '
89
+ lines.push(prefix + selectedLabel + ' \u25BC')
90
+ }
91
+
92
+ return lines
93
+ }
94
+
95
+ export function Select<T>(props: SelectProps<T>): ReactElement {
96
+ return React.createElement('select', props as unknown as Record<string, unknown>)
97
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @mdxui/terminal/components/primitives/text
3
+ *
4
+ * Text component for terminal rendering.
5
+ */
6
+
7
+ import React, { type ReactElement } from 'react'
8
+ import { ANSI } from '../../theme'
9
+ import type { TextProps, RenderContext } from '../types'
10
+ import { extractChildren, getColorCode, getBgColorCode } from '../helpers'
11
+
12
+ export function renderText(props: TextProps, context: RenderContext): string[] {
13
+ const { children, bold, italic, underline, dim, color, backgroundColor, wrap } = props
14
+
15
+ let text = extractChildren(children)
16
+
17
+ // Build style codes
18
+ const codes: string[] = []
19
+ if (bold) codes.push(ANSI.bold)
20
+ if (italic) codes.push(ANSI.italic)
21
+ if (underline) codes.push(ANSI.underline)
22
+ if (dim) codes.push(ANSI.dim)
23
+ if (color) codes.push(getColorCode(color))
24
+ if (backgroundColor) codes.push(getBgColorCode(backgroundColor))
25
+
26
+ // Handle wrapping
27
+ const maxWidth = context.parentWidth || context.width
28
+ if (wrap === 'truncate' && text.length > maxWidth) {
29
+ text = text.slice(0, maxWidth - 1) + '\u2026'
30
+ } else if (wrap === 'wrap' && text.length > maxWidth) {
31
+ // Word wrap
32
+ const lines: string[] = []
33
+ let remaining = text
34
+ while (remaining.length > 0) {
35
+ if (remaining.length <= maxWidth) {
36
+ lines.push(remaining)
37
+ break
38
+ }
39
+ // Find break point
40
+ let breakPoint = maxWidth
41
+ const lastSpace = remaining.lastIndexOf(' ', maxWidth)
42
+ if (lastSpace > 0) breakPoint = lastSpace
43
+ lines.push(remaining.slice(0, breakPoint))
44
+ remaining = remaining.slice(breakPoint).trim()
45
+ }
46
+ // Apply styling to each line
47
+ return lines.map(line => codes.join('') + line + ANSI.reset)
48
+ }
49
+
50
+ // Apply styling
51
+ if (codes.length > 0) {
52
+ return [codes.join('') + text + ANSI.reset]
53
+ }
54
+
55
+ return [text]
56
+ }
57
+
58
+ export function Text(props: TextProps): ReactElement {
59
+ return React.createElement('text', props)
60
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * @mdxui/terminal/components/render
3
+ *
4
+ * Core rendering functions for terminal components.
5
+ */
6
+
7
+ import { type ReactElement } from 'react'
8
+ import type { RenderContext } from './types'
9
+ import {
10
+ isTerminalComponentType,
11
+ isBoxProps,
12
+ isTextProps,
13
+ isTableProps,
14
+ isInputProps,
15
+ isSelectProps,
16
+ isSidebarProps,
17
+ isSidebarItemProps,
18
+ isBreadcrumbProps,
19
+ isBadgeProps,
20
+ isDialogProps,
21
+ isSpinnerProps,
22
+ isButtonProps,
23
+ isPanelProps,
24
+ isListProps,
25
+ isCardProps,
26
+ isPropsObject,
27
+ } from './types'
28
+ import { extractChildren } from './helpers'
29
+ import { renderBox, setRenderElement } from './primitives/box'
30
+ import { renderText } from './primitives/text'
31
+ import { renderInput } from './primitives/input'
32
+ import { renderSelect } from './primitives/select'
33
+ import { renderButton } from './primitives/button'
34
+ import { renderPanel } from './containers/panel'
35
+ import { renderCard } from './containers/card'
36
+ import { renderDialog } from './containers/dialog'
37
+ import { renderSidebar, renderSidebarItem } from './layout/sidebar'
38
+ import { renderBreadcrumb } from './layout/breadcrumb'
39
+ import { renderList } from './layout/list'
40
+ import { renderTable } from './layout/table'
41
+ import { renderBadge } from './feedback/badge'
42
+ import { renderSpinner } from './feedback/spinner'
43
+
44
+ export function renderElement(element: ReactElement, context: RenderContext): string[] {
45
+ const props = element.props
46
+ const type = element.type
47
+
48
+ // Handle function components
49
+ if (typeof type === 'function') {
50
+ const result = (type as (props: unknown) => ReactElement)(props)
51
+ return renderElement(result, context)
52
+ }
53
+
54
+ // Handle terminal component types with proper type guards
55
+ if (isTerminalComponentType(type)) {
56
+ switch (type) {
57
+ case 'box':
58
+ if (isBoxProps(props)) {
59
+ return renderBox(props, context)
60
+ }
61
+ break
62
+ case 'text':
63
+ if (isTextProps(props)) {
64
+ return renderText(props, context)
65
+ }
66
+ break
67
+ case 'table':
68
+ if (isTableProps(props)) {
69
+ return renderTable(props, context)
70
+ }
71
+ break
72
+ case 'input':
73
+ if (isInputProps(props)) {
74
+ return renderInput(props, context)
75
+ }
76
+ break
77
+ case 'select':
78
+ if (isSelectProps(props)) {
79
+ return renderSelect(props, context)
80
+ }
81
+ break
82
+ case 'sidebar':
83
+ if (isSidebarProps(props)) {
84
+ return renderSidebar(props, context)
85
+ }
86
+ break
87
+ case 'sidebar-item':
88
+ if (isSidebarItemProps(props)) {
89
+ return renderSidebarItem(props, context)
90
+ }
91
+ break
92
+ case 'breadcrumb':
93
+ if (isBreadcrumbProps(props)) {
94
+ return renderBreadcrumb(props, context)
95
+ }
96
+ break
97
+ case 'badge':
98
+ if (isBadgeProps(props)) {
99
+ return renderBadge(props, context)
100
+ }
101
+ break
102
+ case 'dialog':
103
+ if (isDialogProps(props)) {
104
+ return renderDialog(props, context)
105
+ }
106
+ break
107
+ case 'spinner':
108
+ if (isSpinnerProps(props)) {
109
+ return renderSpinner(props, context)
110
+ }
111
+ break
112
+ case 'button':
113
+ if (isButtonProps(props)) {
114
+ return renderButton(props, context)
115
+ }
116
+ break
117
+ case 'panel':
118
+ if (isPanelProps(props)) {
119
+ return renderPanel(props, context)
120
+ }
121
+ break
122
+ case 'list':
123
+ if (isListProps(props)) {
124
+ return renderList(props, context)
125
+ }
126
+ break
127
+ case 'card':
128
+ if (isCardProps(props)) {
129
+ return renderCard(props, context)
130
+ }
131
+ break
132
+ }
133
+ }
134
+
135
+ // Generic element rendering for unknown types or failed type guards
136
+ if (isPropsObject(props)) {
137
+ const childText = extractChildren(props.children as import('react').ReactNode)
138
+ return childText ? [childText] : []
139
+ }
140
+
141
+ return []
142
+ }
143
+
144
+ // Initialize circular dependency for box component
145
+ setRenderElement(renderElement)
146
+
147
+ /**
148
+ * Render a React element to terminal output strings
149
+ */
150
+ export function renderComponent(element: ReactElement): string[] {
151
+ const context: RenderContext = { width: 80 }
152
+ return renderElement(element, context)
153
+ }
154
+
155
+ export type { RenderContext }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @mdxui/terminal/components/templates/app
3
+ *
4
+ * App template components (mdxui AppComponents interface).
5
+ */
6
+
7
+ import React, { type ReactElement } from 'react'
8
+ import type {
9
+ AppProps,
10
+ ShellProps,
11
+ SidebarProps,
12
+ AppHeaderProps,
13
+ DashboardProps,
14
+ SettingsProps,
15
+ } from '../types'
16
+
17
+ export function App(props: AppProps): ReactElement {
18
+ return React.createElement('app', props)
19
+ }
20
+
21
+ export function Shell(props: ShellProps): ReactElement {
22
+ return React.createElement('shell', props)
23
+ }
24
+
25
+ export function Sidebar(props: SidebarProps): ReactElement {
26
+ return React.createElement('sidebar', props)
27
+ }
28
+
29
+ /**
30
+ * AppHeader component for the top header bar.
31
+ * Note: The test imports this as Header but it uses AppHeaderProps.
32
+ */
33
+ export function AppHeader(props: AppHeaderProps): ReactElement {
34
+ return React.createElement('app-header', props)
35
+ }
36
+
37
+ export function Dashboard(props: DashboardProps): ReactElement {
38
+ return React.createElement('dashboard', props)
39
+ }
40
+
41
+ export function Settings(props: SettingsProps): ReactElement {
42
+ return React.createElement('settings', props)
43
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @mdxui/terminal/components/templates
3
+ *
4
+ * Template components for mdxui Site and App interfaces.
5
+ */
6
+
7
+ export { Site, Header, Footer, Hero, Features, Pricing, FAQ, LandingPage, Page } from './site'
8
+ export { App, Shell, Sidebar, AppHeader, Dashboard, Settings } from './app'
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @mdxui/terminal/components/templates/site
3
+ *
4
+ * Site template components (mdxui SiteComponents interface).
5
+ */
6
+
7
+ import React, { type ReactElement } from 'react'
8
+ import type {
9
+ SiteProps,
10
+ HeaderProps,
11
+ FooterProps,
12
+ HeroProps,
13
+ FeaturesProps,
14
+ PricingProps,
15
+ FAQProps,
16
+ LandingPageProps,
17
+ PageProps,
18
+ } from '../types'
19
+
20
+ export function Site(props: SiteProps): ReactElement {
21
+ return React.createElement('site', props)
22
+ }
23
+
24
+ export function Header(props: HeaderProps): ReactElement {
25
+ return React.createElement('header', props)
26
+ }
27
+
28
+ export function Footer(props: FooterProps): ReactElement {
29
+ return React.createElement('footer', props)
30
+ }
31
+
32
+ export function Hero(props: HeroProps): ReactElement {
33
+ return React.createElement('hero', props)
34
+ }
35
+
36
+ export function Features(props: FeaturesProps): ReactElement {
37
+ return React.createElement('features', props)
38
+ }
39
+
40
+ export function Pricing(props: PricingProps): ReactElement {
41
+ return React.createElement('pricing', props)
42
+ }
43
+
44
+ export function FAQ(props: FAQProps): ReactElement {
45
+ return React.createElement('faq', props)
46
+ }
47
+
48
+ export function LandingPage(props: LandingPageProps): ReactElement {
49
+ return React.createElement('landing-page', props)
50
+ }
51
+
52
+ export function Page(props: PageProps): ReactElement {
53
+ return React.createElement('page', props)
54
+ }