@visulima/tui-kit 0.0.0 → 1.0.1
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.
- package/CHANGELOG.md +13 -0
- package/LICENSE.md +2095 -0
- package/README.md +115 -29
- package/dist/accordion.d.ts +52 -0
- package/dist/accordion.js +1 -0
- package/dist/alert.d.ts +22 -0
- package/dist/alert.js +1 -0
- package/dist/animate-presence.d.ts +16 -0
- package/dist/animate-presence.js +1 -0
- package/dist/approval-prompt.d.ts +55 -0
- package/dist/approval-prompt.js +1 -0
- package/dist/area-chart.d.ts +56 -0
- package/dist/area-chart.js +1 -0
- package/dist/badge.d.ts +19 -0
- package/dist/badge.js +1 -0
- package/dist/bar-chart.d.ts +58 -0
- package/dist/bar-chart.js +1 -0
- package/dist/big-text.d.ts +71 -0
- package/dist/big-text.js +1 -0
- package/dist/blink-dot.d.ts +31 -0
- package/dist/blink-dot.js +1 -0
- package/dist/breadcrumb.d.ts +29 -0
- package/dist/breadcrumb.js +1 -0
- package/dist/button.d.ts +38 -0
- package/dist/button.js +1 -0
- package/dist/calendar.d.ts +60 -0
- package/dist/calendar.js +1 -0
- package/dist/card.d.ts +47 -0
- package/dist/card.js +1 -0
- package/dist/checkbox-group.d.ts +50 -0
- package/dist/checkbox-group.js +1 -0
- package/dist/checkbox.d.ts +40 -0
- package/dist/checkbox.js +1 -0
- package/dist/code.d.ts +41 -0
- package/dist/code.js +2 -0
- package/dist/collapsible.d.ts +44 -0
- package/dist/collapsible.js +1 -0
- package/dist/color-picker.d.ts +59 -0
- package/dist/color-picker.js +1 -0
- package/dist/command-block.d.ts +39 -0
- package/dist/command-block.js +4 -0
- package/dist/command-palette.d.ts +73 -0
- package/dist/command-palette.js +1 -0
- package/dist/confirm-dialog.d.ts +63 -0
- package/dist/confirm-dialog.js +1 -0
- package/dist/confirm-input.d.ts +32 -0
- package/dist/confirm-input.js +1 -0
- package/dist/console-overlay.d.ts +47 -0
- package/dist/console-overlay.js +1 -0
- package/dist/content-switcher.d.ts +49 -0
- package/dist/content-switcher.js +1 -0
- package/dist/controlled-scroll-view.d.ts +3 -0
- package/dist/controlled-scroll-view.js +1 -0
- package/dist/data-grid.d.ts +43 -0
- package/dist/data-grid.js +1 -0
- package/dist/date-picker.d.ts +54 -0
- package/dist/date-picker.js +1 -0
- package/dist/definition-list.d.ts +38 -0
- package/dist/definition-list.js +1 -0
- package/dist/dialog.d.ts +94 -0
- package/dist/dialog.js +1 -0
- package/dist/diff-view.d.ts +72 -0
- package/dist/diff-view.js +1 -0
- package/dist/digits.d.ts +26 -0
- package/dist/digits.js +1 -0
- package/dist/directory-tree.d.ts +44 -0
- package/dist/directory-tree.js +1 -0
- package/dist/divider.d.ts +41 -0
- package/dist/divider.js +1 -0
- package/dist/drawer.d.ts +45 -0
- package/dist/drawer.js +1 -0
- package/dist/file-change.d.ts +34 -0
- package/dist/file-change.js +1 -0
- package/dist/file-picker-entry.d.ts +2 -0
- package/dist/file-picker-entry.js +1 -0
- package/dist/form.d.ts +74 -0
- package/dist/form.js +1 -0
- package/dist/gauge.d.ts +76 -0
- package/dist/gauge.js +1 -0
- package/dist/gradient.d.ts +38 -0
- package/dist/gradient.js +1 -0
- package/dist/grid.d.ts +34 -0
- package/dist/grid.js +1 -0
- package/dist/heading.d.ts +28 -0
- package/dist/heading.js +1 -0
- package/dist/heatmap.d.ts +52 -0
- package/dist/heatmap.js +1 -0
- package/dist/help.d.ts +45 -0
- package/dist/help.js +1 -0
- package/dist/histogram.d.ts +52 -0
- package/dist/histogram.js +1 -0
- package/dist/image.d.ts +23 -0
- package/dist/image.js +1 -0
- package/dist/index.d.ts +125 -0
- package/dist/index.js +1 -0
- package/dist/json.d.ts +51 -0
- package/dist/json.js +1 -0
- package/dist/kbd.d.ts +27 -0
- package/dist/kbd.js +1 -0
- package/dist/line-chart.d.ts +100 -0
- package/dist/line-chart.js +1 -0
- package/dist/link.d.ts +34 -0
- package/dist/link.js +1 -0
- package/dist/loading-indicator.d.ts +25 -0
- package/dist/loading-indicator.js +1 -0
- package/dist/log.d.ts +33 -0
- package/dist/log.js +1 -0
- package/dist/markdown.d.ts +35 -0
- package/dist/markdown.js +1 -0
- package/dist/masked-input.d.ts +42 -0
- package/dist/masked-input.js +1 -0
- package/dist/menu.d.ts +70 -0
- package/dist/menu.js +1 -0
- package/dist/message-bubble.d.ts +36 -0
- package/dist/message-bubble.js +1 -0
- package/dist/model-badge.d.ts +33 -0
- package/dist/model-badge.js +1 -0
- package/dist/model-selector.d.ts +45 -0
- package/dist/model-selector.js +1 -0
- package/dist/multi-progress.d.ts +48 -0
- package/dist/multi-progress.js +1 -0
- package/dist/multi-select.d.ts +55 -0
- package/dist/multi-select.js +1 -0
- package/dist/notification-badge.d.ts +40 -0
- package/dist/notification-badge.js +1 -0
- package/dist/number-input.d.ts +71 -0
- package/dist/number-input.js +1 -0
- package/dist/operation-tree.d.ts +46 -0
- package/dist/operation-tree.js +1 -0
- package/dist/option-list.d.ts +41 -0
- package/dist/option-list.js +1 -0
- package/dist/ordered-list.d.ts +22 -0
- package/dist/ordered-list.js +1 -0
- package/dist/packem_shared/ControlledScrollView-BzlbIUph.js +1 -0
- package/dist/packem_shared/FilePicker-V5H2fb-v.js +1 -0
- package/dist/packem_shared/ScrollBar-C9i3z3Ft.js +1 -0
- package/dist/packem_shared/ScrollBarBox-DZEC8YnV.js +1 -0
- package/dist/packem_shared/ScrollList-Djtb2vVy.js +1 -0
- package/dist/packem_shared/ScrollView-ESxpl6Hy.js +1 -0
- package/dist/packem_shared/TreeNodeMap-cJlYqckB.js +1 -0
- package/dist/packem_shared/TreeView-q0l446NV.js +1 -0
- package/dist/packem_shared/controlled-scroll-view-DerVKKv6.js +1 -0
- package/dist/packem_shared/controlled-scroll-view.d-D3kZZzjI.d.ts +43 -0
- package/dist/packem_shared/file-picker.d-CH7pccC7.d.ts +92 -0
- package/dist/packem_shared/line-chart-BbhMhcZg.js +1 -0
- package/dist/packem_shared/scroll-bar-box.d-CpTYEcTZ.d.ts +13 -0
- package/dist/packem_shared/scroll-bar.d-B4sD1hBR.d.ts +18 -0
- package/dist/packem_shared/scroll-list.d-CPCF0RwC.d.ts +12 -0
- package/dist/packem_shared/scroll-view.d-GZcgAHl4.d.ts +98 -0
- package/dist/packem_shared/treeViewTheme-Dq3ekRAC.js +1 -0
- package/dist/packem_shared/use-tree-view.d-DeMQ6G2r.d.ts +314 -0
- package/dist/packem_shared/useTreeView-D0JEqT6W.js +1 -0
- package/dist/packem_shared/useTreeViewState-BiTJakkh.js +1 -0
- package/dist/packem_shared/variant-config-BJqpNo7H.js +1 -0
- package/dist/packem_shared/variant-config.d-D5NnrrQK.d.ts +2 -0
- package/dist/paginator.d.ts +59 -0
- package/dist/paginator.js +1 -0
- package/dist/paragraph.d.ts +32 -0
- package/dist/paragraph.js +1 -0
- package/dist/path-input.d.ts +56 -0
- package/dist/path-input.js +1 -0
- package/dist/pie-chart.d.ts +44 -0
- package/dist/pie-chart.js +1 -0
- package/dist/placeholder.d.ts +47 -0
- package/dist/placeholder.js +1 -0
- package/dist/popover.d.ts +39 -0
- package/dist/popover.js +1 -0
- package/dist/progress-bar.d.ts +43 -0
- package/dist/progress-bar.js +1 -0
- package/dist/progress-circle.d.ts +50 -0
- package/dist/progress-circle.js +1 -0
- package/dist/qr-code.d.ts +39 -0
- package/dist/qr-code.js +1 -0
- package/dist/r/accordion.json +24 -0
- package/dist/r/alert.json +24 -0
- package/dist/r/animate-presence.json +22 -0
- package/dist/r/approval-prompt.json +24 -0
- package/dist/r/area-chart.json +27 -0
- package/dist/r/badge.json +24 -0
- package/dist/r/bar-chart.json +24 -0
- package/dist/r/big-text.json +23 -0
- package/dist/r/blink-dot.json +24 -0
- package/dist/r/breadcrumb.json +24 -0
- package/dist/r/button.json +24 -0
- package/dist/r/calendar.json +24 -0
- package/dist/r/card.json +26 -0
- package/dist/r/chart-utils.json +24 -0
- package/dist/r/checkbox-group.json +24 -0
- package/dist/r/checkbox.json +24 -0
- package/dist/r/code.json +23 -0
- package/dist/r/collapsible.json +24 -0
- package/dist/r/color-picker.json +24 -0
- package/dist/r/command-block.json +26 -0
- package/dist/r/command-palette.json +24 -0
- package/dist/r/confirm-dialog.json +24 -0
- package/dist/r/confirm-input.json +22 -0
- package/dist/r/console-overlay.json +22 -0
- package/dist/r/content-switcher.json +24 -0
- package/dist/r/controlled-scroll-view.json +24 -0
- package/dist/r/data-grid.json +24 -0
- package/dist/r/date-picker.json +26 -0
- package/dist/r/definition-list.json +24 -0
- package/dist/r/dialog.json +24 -0
- package/dist/r/diff-view.json +24 -0
- package/dist/r/digits.json +24 -0
- package/dist/r/directory-tree.json +24 -0
- package/dist/r/divider.json +24 -0
- package/dist/r/drawer.json +24 -0
- package/dist/r/file-change.json +24 -0
- package/dist/r/file-picker.json +44 -0
- package/dist/r/form.json +24 -0
- package/dist/r/gauge.json +24 -0
- package/dist/r/gradient.json +24 -0
- package/dist/r/grid.json +22 -0
- package/dist/r/heading.json +24 -0
- package/dist/r/heatmap.json +24 -0
- package/dist/r/help.json +22 -0
- package/dist/r/histogram.json +26 -0
- package/dist/r/image.json +24 -0
- package/dist/r/json.json +24 -0
- package/dist/r/kbd.json +24 -0
- package/dist/r/line-chart.json +26 -0
- package/dist/r/link.json +23 -0
- package/dist/r/loading-indicator.json +27 -0
- package/dist/r/log.json +24 -0
- package/dist/r/markdown.json +29 -0
- package/dist/r/masked-input.json +22 -0
- package/dist/r/menu.json +24 -0
- package/dist/r/message-bubble.json +24 -0
- package/dist/r/model-badge.json +24 -0
- package/dist/r/model-selector.json +24 -0
- package/dist/r/multi-progress.json +24 -0
- package/dist/r/multi-select.json +24 -0
- package/dist/r/notification-badge.json +24 -0
- package/dist/r/number-input.json +24 -0
- package/dist/r/operation-tree.json +26 -0
- package/dist/r/option-list.json +24 -0
- package/dist/r/ordered-list.json +22 -0
- package/dist/r/paginator.json +22 -0
- package/dist/r/paragraph.json +24 -0
- package/dist/r/path-input.json +26 -0
- package/dist/r/pie-chart.json +24 -0
- package/dist/r/placeholder.json +24 -0
- package/dist/r/popover.json +24 -0
- package/dist/r/progress-bar.json +22 -0
- package/dist/r/progress-circle.json +24 -0
- package/dist/r/qr-code.json +24 -0
- package/dist/r/radio-group.json +24 -0
- package/dist/r/registry.json +1051 -0
- package/dist/r/scatter-plot.json +27 -0
- package/dist/r/scroll-bar-box.json +24 -0
- package/dist/r/scroll-bar.json +24 -0
- package/dist/r/scroll-list.json +24 -0
- package/dist/r/scroll-view.json +24 -0
- package/dist/r/scroll.json +58 -0
- package/dist/r/search-input.json +26 -0
- package/dist/r/select-input-indicator.json +24 -0
- package/dist/r/select-input-item.json +24 -0
- package/dist/r/select-input.json +28 -0
- package/dist/r/shimmer-text.json +24 -0
- package/dist/r/sidebar.json +24 -0
- package/dist/r/slider.json +24 -0
- package/dist/r/sparkline.json +24 -0
- package/dist/r/spinner.json +23 -0
- package/dist/r/status-line.json +24 -0
- package/dist/r/status-message.json +24 -0
- package/dist/r/stepper.json +24 -0
- package/dist/r/stopwatch.json +22 -0
- package/dist/r/streaming-text.json +24 -0
- package/dist/r/switch.json +24 -0
- package/dist/r/tab.json +22 -0
- package/dist/r/table.json +23 -0
- package/dist/r/tabs.json +26 -0
- package/dist/r/tag-input.json +24 -0
- package/dist/r/tag.json +24 -0
- package/dist/r/text-input.json +22 -0
- package/dist/r/textarea.json +22 -0
- package/dist/r/thinking-block.json +24 -0
- package/dist/r/time-picker.json +24 -0
- package/dist/r/timer.json +22 -0
- package/dist/r/toast.json +24 -0
- package/dist/r/token-usage.json +24 -0
- package/dist/r/tool-call.json +24 -0
- package/dist/r/tooltip.json +24 -0
- package/dist/r/transition.json +22 -0
- package/dist/r/tree-select.json +24 -0
- package/dist/r/tree-view.json +64 -0
- package/dist/r/unordered-list.json +22 -0
- package/dist/r/use-linked-scroll.json +24 -0
- package/dist/r/variant-config.json +22 -0
- package/dist/radio-group.d.ts +63 -0
- package/dist/radio-group.js +1 -0
- package/dist/scatter-plot.d.ts +24 -0
- package/dist/scatter-plot.js +1 -0
- package/dist/scroll-bar-box.d.ts +3 -0
- package/dist/scroll-bar-box.js +1 -0
- package/dist/scroll-bar.d.ts +3 -0
- package/dist/scroll-bar.js +1 -0
- package/dist/scroll-list.d.ts +4 -0
- package/dist/scroll-list.js +1 -0
- package/dist/scroll-view.d.ts +3 -0
- package/dist/scroll-view.js +1 -0
- package/dist/search-input.d.ts +46 -0
- package/dist/search-input.js +1 -0
- package/dist/select-input-indicator.d.ts +28 -0
- package/dist/select-input-indicator.js +1 -0
- package/dist/select-input-item.d.ts +35 -0
- package/dist/select-input-item.js +1 -0
- package/dist/select-input.d.ts +97 -0
- package/dist/select-input.js +1 -0
- package/dist/shimmer-text.d.ts +41 -0
- package/dist/shimmer-text.js +1 -0
- package/dist/sidebar.d.ts +40 -0
- package/dist/sidebar.js +1 -0
- package/dist/slider.d.ts +87 -0
- package/dist/slider.js +1 -0
- package/dist/sparkline.d.ts +36 -0
- package/dist/sparkline.js +1 -0
- package/dist/spinner.d.ts +15 -0
- package/dist/spinner.js +1 -0
- package/dist/status-line.d.ts +31 -0
- package/dist/status-line.js +1 -0
- package/dist/status-message.d.ts +18 -0
- package/dist/status-message.js +1 -0
- package/dist/stepper.d.ts +42 -0
- package/dist/stepper.js +1 -0
- package/dist/stopwatch.d.ts +42 -0
- package/dist/stopwatch.js +1 -0
- package/dist/streaming-text.d.ts +39 -0
- package/dist/streaming-text.js +1 -0
- package/dist/switch.d.ts +46 -0
- package/dist/switch.js +1 -0
- package/dist/tab.d.ts +17 -0
- package/dist/tab.js +1 -0
- package/dist/table.d.ts +118 -0
- package/dist/table.js +1 -0
- package/dist/tabs.d.ts +96 -0
- package/dist/tabs.js +1 -0
- package/dist/tag-input.d.ts +59 -0
- package/dist/tag-input.js +1 -0
- package/dist/tag.d.ts +30 -0
- package/dist/tag.js +1 -0
- package/dist/text-input.d.ts +40 -0
- package/dist/text-input.js +1 -0
- package/dist/textarea.d.ts +57 -0
- package/dist/textarea.js +2 -0
- package/dist/thinking-block.d.ts +48 -0
- package/dist/thinking-block.js +1 -0
- package/dist/time-picker.d.ts +57 -0
- package/dist/time-picker.js +1 -0
- package/dist/timer.d.ts +50 -0
- package/dist/timer.js +1 -0
- package/dist/toast.d.ts +41 -0
- package/dist/toast.js +1 -0
- package/dist/token-usage.d.ts +43 -0
- package/dist/token-usage.js +1 -0
- package/dist/tool-call.d.ts +28 -0
- package/dist/tool-call.js +1 -0
- package/dist/tooltip.d.ts +37 -0
- package/dist/tooltip.js +1 -0
- package/dist/transition.d.ts +66 -0
- package/dist/transition.js +1 -0
- package/dist/tree-select.d.ts +55 -0
- package/dist/tree-select.js +1 -0
- package/dist/tree-view-entry.d.ts +4 -0
- package/dist/tree-view-entry.js +1 -0
- package/dist/unordered-list.d.ts +27 -0
- package/dist/unordered-list.js +1 -0
- package/dist/use-linked-scroll.d.ts +42 -0
- package/dist/use-linked-scroll.js +1 -0
- package/package.json +553 -7
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "progress-bar",
|
|
4
|
+
"type": "registry:ui",
|
|
5
|
+
"title": "Progress Bar",
|
|
6
|
+
"description": "Progress Bar component for @visulima/tui.",
|
|
7
|
+
"categories": [
|
|
8
|
+
"ui"
|
|
9
|
+
],
|
|
10
|
+
"dependencies": [
|
|
11
|
+
"@visulima/tui"
|
|
12
|
+
],
|
|
13
|
+
"registryDependencies": [],
|
|
14
|
+
"files": [
|
|
15
|
+
{
|
|
16
|
+
"content": "/* eslint-disable react/function-component-definition */\n\n/**\n * Progress bar component for Ink.\n *\n * Based on ink-progress-bar by Frankie Bagnardi (brigand).\n * @see https://github.com/brigand/ink-progress-bar\n *\n * MIT License\n * Copyright (c) Frankie Bagnardi\n */\nimport type { Props as TextProps } from \"@visulima/tui/components/text\";\nimport Text from \"@visulima/tui/components/text\";\nimport useWindowSize from \"@visulima/tui/hooks/use-window-size\";\nimport type { ReactElement } from \"react\";\n\nexport type Props = {\n /** Fill glyph repeated across the completed portion of the progress bar. Defaults to \"█\". */\n readonly character?: string;\n\n /**\n * Override the terminal width used for calculation.\n * When 0, uses the actual terminal width.\n * @default 0\n */\n readonly columns?: number;\n\n /**\n * Number of columns reserved on the left side (e.g. for labels).\n * @default 0\n */\n readonly left?: number;\n\n /**\n * Completion percentage between 0 and 1.\n * @default 1\n */\n readonly percent?: number;\n\n /**\n * Number of columns reserved on the right side (e.g. for percentage text).\n * @default 0\n */\n readonly right?: number;\n\n /**\n * Whether to pad the remaining space with whitespace.\n * Useful when rendering the bar over a background color.\n * @default false\n */\n readonly rightPad?: boolean;\n} & Omit<TextProps, \"children\">;\n\n/**\n * A terminal progress bar that fills proportionally to a percentage value.\n *\n * ```tsx\n * <ProgressBar percent={0.5} />\n * <ProgressBar percent={0.75} color=\"green\" left={10} right={5} />\n * ```\n */\nexport default function ProgressBar({\n character = \"\\u2588\",\n columns: columnsProp = 0,\n left = 0,\n percent = 1,\n right = 0,\n rightPad = false,\n ...textProps\n}: Props): ReactElement {\n const { columns: terminalColumns } = useWindowSize();\n\n const screen = columnsProp || terminalColumns || 80;\n const space = Math.max(0, screen - right - left);\n const filled = Math.min(Math.floor(space * Math.max(0, Math.min(1, percent))), space);\n const bar = character.repeat(filled) + (rightPad ? \" \".repeat(space - filled) : \"\");\n\n return <Text {...textProps}>{bar}</Text>;\n}\n\nexport { ProgressBar };\nexport type { Props as ProgressBarProps };\n",
|
|
17
|
+
"path": "registry/ui/progress-bar.tsx",
|
|
18
|
+
"target": "components/ui/progress-bar.tsx",
|
|
19
|
+
"type": "registry:ui"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "progress-circle",
|
|
4
|
+
"type": "registry:ui",
|
|
5
|
+
"title": "Progress Circle",
|
|
6
|
+
"description": "Progress Circle component for @visulima/tui.",
|
|
7
|
+
"categories": [
|
|
8
|
+
"ui"
|
|
9
|
+
],
|
|
10
|
+
"dependencies": [
|
|
11
|
+
"@visulima/colorize",
|
|
12
|
+
"@visulima/tui",
|
|
13
|
+
"type-fest"
|
|
14
|
+
],
|
|
15
|
+
"registryDependencies": [],
|
|
16
|
+
"files": [
|
|
17
|
+
{
|
|
18
|
+
"content": "/* eslint-disable react/function-component-definition */\nimport type { AnsiColors } from \"@visulima/colorize\";\nimport type { CanvasContext } from \"@visulima/tui/canvas\";\nimport { createBrailleGrid } from \"@visulima/tui/canvas\";\nimport Box from \"@visulima/tui/components/box\";\nimport Canvas from \"@visulima/tui/components/canvas\";\nimport Text from \"@visulima/tui/components/text\";\nimport type { ReactElement } from \"react\";\nimport type { LiteralUnion } from \"type-fest\";\n\nexport type Props = {\n /**\n * Color of the filled portion of the ring.\n * @default \"cyan\"\n */\n readonly color?: LiteralUnion<AnsiColors, string>;\n\n /**\n * Format the centered readout. Defaults to a rounded percentage.\n */\n readonly formatValue?: (ratio: number) => string;\n\n /**\n * Upper bound of the range.\n * @default 100\n */\n readonly max?: number;\n\n /**\n * Lower bound of the range.\n * @default 0\n */\n readonly min?: number;\n\n /**\n * Show the readout in the middle of the ring.\n * @default true\n */\n readonly showValue?: boolean;\n\n /**\n * Diameter of the ring in character rows.\n * @default 8\n */\n readonly size?: number;\n\n /**\n * Color of the unfilled track behind the ring.\n * @default \"gray\"\n */\n readonly trackColor?: LiteralUnion<AnsiColors, string>;\n\n /**\n * Current value, clamped into `[min, max]`.\n */\n readonly value: number;\n};\n\nconst defaultFormat = (ratio: number): string => `${Math.round(ratio * 100)}%`;\n\n/**\n * A circular progress ring rendered at 2x4 braille sub-cell resolution. The\n * filled arc grows clockwise from the top in proportion to `value`, with an\n * optional centered readout.\n */\nexport default function ProgressCircle({\n color = \"cyan\",\n formatValue = defaultFormat,\n max = 100,\n min = 0,\n showValue = true,\n size = 8,\n trackColor = \"gray\",\n value,\n}: Props): ReactElement {\n const range = max - min || 1;\n const ratio = Math.max(0, Math.min(1, (value - min) / range));\n\n const rows = Math.max(3, size);\n const cols = Math.max(3, Math.round((rows * 4) / 2 / 2));\n\n return (\n <Box alignItems=\"center\" flexDirection=\"column\">\n <Canvas\n // eslint-disable-next-line react-perf/jsx-no-new-function-as-prop -- canvas re-renders on `version` change, not draw identity\n draw={(context: CanvasContext) => {\n context.clear();\n\n const pixelWidth = context.width * 2;\n const pixelHeight = context.height * 4;\n const cx = pixelWidth / 2;\n const cy = pixelHeight / 2;\n const radius = Math.max(1, Math.min(cx, cy) - 1);\n\n const trackGrid = createBrailleGrid(context.width, context.height);\n const fillGrid = createBrailleGrid(context.width, context.height);\n\n const steps = Math.max(64, Math.round(Math.PI * 2 * radius));\n const filledSteps = Math.round(ratio * steps);\n\n for (let step = 0; step < steps; step += 1) {\n // Clockwise from the top.\n const angle = (step / steps) * Math.PI * 2 - Math.PI / 2;\n const px = Math.round(cx + radius * Math.cos(angle));\n const py = Math.round(cy + radius * Math.sin(angle));\n\n (step < filledSteps ? fillGrid : trackGrid).plotPoint(px, py);\n }\n\n trackGrid.flush(context, { color: trackColor });\n fillGrid.flush(context, { color });\n }}\n height={rows}\n // eslint-disable-next-line react-perf/jsx-no-new-array-as-prop -- version array is the canvas redraw key\n version={[value, min, max, size, color, trackColor]}\n width={cols}\n />\n {showValue\n ? (\n <Box marginTop={-Math.ceil(rows / 2) - 1}>\n <Text bold color={color}>\n {formatValue(ratio)}\n </Text>\n </Box>\n )\n : undefined}\n </Box>\n );\n}\n\nexport { ProgressCircle };\nexport type { Props as ProgressCircleProps };\n",
|
|
19
|
+
"path": "registry/ui/progress-circle.tsx",
|
|
20
|
+
"target": "components/ui/progress-circle.tsx",
|
|
21
|
+
"type": "registry:ui"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "qr-code",
|
|
4
|
+
"type": "registry:ui",
|
|
5
|
+
"title": "Qr Code",
|
|
6
|
+
"description": "Qr Code component for @visulima/tui.",
|
|
7
|
+
"categories": [
|
|
8
|
+
"ui"
|
|
9
|
+
],
|
|
10
|
+
"dependencies": [
|
|
11
|
+
"@visulima/colorize",
|
|
12
|
+
"@visulima/tui",
|
|
13
|
+
"type-fest"
|
|
14
|
+
],
|
|
15
|
+
"registryDependencies": [],
|
|
16
|
+
"files": [
|
|
17
|
+
{
|
|
18
|
+
"content": "/* eslint-disable react/function-component-definition */\nimport type { AnsiColors } from \"@visulima/colorize\";\nimport Box from \"@visulima/tui/components/box\";\nimport Text from \"@visulima/tui/components/text\";\nimport type { ReactElement } from \"react\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { LiteralUnion } from \"type-fest\";\n\ntype Color = LiteralUnion<AnsiColors, string>;\n\nexport type Props = {\n /**\n * Color of the \"dark\" modules.\n * @default \"black\"\n */\n readonly darkColor?: Color;\n\n /**\n * Color of the \"light\" modules and quiet zone.\n * @default \"white\"\n */\n readonly lightColor?: Color;\n\n /**\n * A pre-encoded square grid of modules (`true` = dark). Provide this to\n * render without the optional `qrcode` peer; it takes precedence over\n * `value`.\n */\n readonly matrix?: ReadonlyArray<ReadonlyArray<boolean>>;\n\n /**\n * Width of the light border around the code, in modules.\n * @default 2\n */\n readonly quietZone?: number;\n\n /**\n * A string to encode. Requires the optional `qrcode` peer dependency; when\n * absent, provide `matrix` instead.\n */\n readonly value?: string;\n};\n\nconst UPPER_HALF = \"▀\";\n\n/** Pad a module matrix with a light quiet zone on all sides. */\nconst withQuietZone = (matrix: ReadonlyArray<ReadonlyArray<boolean>>, zone: number): boolean[][] => {\n if (zone <= 0) {\n return matrix.map((row) => [...row]);\n }\n\n let maxWidth = 0;\n\n for (const row of matrix) {\n maxWidth = Math.max(maxWidth, row.length);\n }\n\n const width = maxWidth + zone * 2;\n const blankRow = (): boolean[] => {\n const row: boolean[] = [];\n\n for (let index = 0; index < width; index += 1) {\n row.push(false);\n }\n\n return row;\n };\n const out: boolean[][] = [];\n\n for (let index = 0; index < zone; index += 1) {\n out.push(blankRow());\n }\n\n for (const row of matrix) {\n const padded = blankRow();\n\n row.forEach((cell, index) => {\n padded[index + zone] = cell;\n });\n\n out.push(padded);\n }\n\n for (let index = 0; index < zone; index += 1) {\n out.push(blankRow());\n }\n\n return out;\n};\n\n/**\n * Render a QR code from a module matrix using the upper-half-block technique,\n * so two module rows share one character row. Pass `matrix` for a self-contained\n * render, or `value` to encode a string via the optional `qrcode` peer.\n */\nexport default function QrCode({ darkColor = \"black\", lightColor = \"white\", matrix, quietZone = 2, value }: Props): ReactElement {\n const [encoded, setEncoded] = useState<ReadonlyArray<ReadonlyArray<boolean>> | undefined>(undefined);\n\n useEffect(() => {\n if (matrix !== undefined || value === undefined) {\n return undefined;\n }\n\n let cancelled = false;\n\n const encode = async (): Promise<void> => {\n try {\n // Optional peer — only needed for the string-encoding path.\n const qrcode = (await import(\"qrcode\")) as unknown as {\n create: (text: string) => { modules: { data: Uint8Array | number[]; size: number } };\n };\n const { modules } = qrcode.create(value);\n const grid: boolean[][] = [];\n\n for (let y = 0; y < modules.size; y += 1) {\n const row: boolean[] = [];\n\n for (let x = 0; x < modules.size; x += 1) {\n row.push(Boolean(modules.data[y * modules.size + x]));\n }\n\n grid.push(row);\n }\n\n if (!cancelled) {\n setEncoded(grid);\n }\n } catch {\n // qrcode not installed — nothing to render from `value`.\n }\n };\n\n // eslint-disable-next-line react-you-might-not-need-an-effect/no-external-store-subscription -- lazily loads the optional `qrcode` peer, not a subscribable store\n encode().catch(() => {\n // Swallow: the string-encoding path is best-effort.\n });\n\n return () => {\n cancelled = true;\n };\n }, [matrix, value]);\n\n const source = matrix ?? encoded;\n const padded = useMemo(() => {\n if (source === undefined) {\n return undefined;\n }\n\n return withQuietZone(source, quietZone);\n }, [quietZone, source]);\n\n if (padded === undefined) {\n return (\n <Box>\n <Text dimColor>{value === undefined ? \"\" : \"Encoding…\"}</Text>\n </Box>\n );\n }\n\n const rows: ReactElement[] = [];\n\n for (let y = 0; y < padded.length; y += 2) {\n const top = padded[y] ?? [];\n const bottom = padded[y + 1] ?? [];\n const spans: ReactElement[] = [];\n\n for (const [x, element] of top.entries()) {\n spans.push(\n\n <Text backgroundColor={bottom[x] ? darkColor : lightColor} color={element ? darkColor : lightColor} key={x}>\n {UPPER_HALF}\n </Text>,\n );\n }\n\n rows.push(\n\n <Box key={y}>{spans}</Box>,\n );\n }\n\n return <Box flexDirection=\"column\">{rows}</Box>;\n}\n\nexport { QrCode };\nexport type { Props as QrCodeProps };\n",
|
|
19
|
+
"path": "registry/ui/qr-code.tsx",
|
|
20
|
+
"target": "components/ui/qr-code.tsx",
|
|
21
|
+
"type": "registry:ui"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "radio-group",
|
|
4
|
+
"type": "registry:ui",
|
|
5
|
+
"title": "Radio Group",
|
|
6
|
+
"description": "Radio Group component for @visulima/tui.",
|
|
7
|
+
"categories": [
|
|
8
|
+
"ui"
|
|
9
|
+
],
|
|
10
|
+
"dependencies": [
|
|
11
|
+
"@visulima/colorize",
|
|
12
|
+
"@visulima/tui",
|
|
13
|
+
"type-fest"
|
|
14
|
+
],
|
|
15
|
+
"registryDependencies": [],
|
|
16
|
+
"files": [
|
|
17
|
+
{
|
|
18
|
+
"content": "/* eslint-disable react/function-component-definition */\nimport type { AnsiColors } from \"@visulima/colorize\";\nimport Box from \"@visulima/tui/components/box\";\nimport Text from \"@visulima/tui/components/text\";\nimport useFocus from \"@visulima/tui/hooks/use-focus\";\nimport useInput from \"@visulima/tui/hooks/use-input\";\nimport type { ReactElement } from \"react\";\nimport { useCallback, useRef, useState } from \"react\";\nimport type { LiteralUnion } from \"type-fest\";\n\nexport type RadioOption = {\n readonly description?: string;\n readonly key?: string;\n readonly label: string;\n readonly value: string;\n};\n\nexport type Props = {\n /**\n * Accent color for the focused and selected indicator.\n * @default \"blue\"\n */\n readonly accentColor?: LiteralUnion<AnsiColors, string>;\n\n /**\n * Auto-focus when mounted.\n */\n readonly autoFocus?: boolean;\n\n /**\n * When true, moving focus with arrow keys immediately updates the selected\n * value (and fires `onChange`). When false, focus moves independently and\n * selection commits only on Space or Enter.\n * @default true\n */\n readonly commitOnNavigate?: boolean;\n\n /**\n * Initial selected value when uncontrolled.\n */\n readonly defaultValue?: string;\n\n /**\n * Disable input and dim labels.\n */\n readonly isDisabled?: boolean;\n\n /**\n * Called when selection changes.\n */\n readonly onChange?: (value: string) => void;\n\n /**\n * Called when the user submits by pressing Enter.\n */\n readonly onSubmit?: (value: string) => void;\n\n /**\n * Available options.\n */\n readonly options: ReadonlyArray<RadioOption>;\n\n /**\n * Orientation of options.\n * @default \"vertical\"\n */\n readonly orientation?: \"horizontal\" | \"vertical\";\n\n /**\n * Controlled selected value.\n */\n readonly value?: string;\n};\n\nconst initialFocusIndex = (options: ReadonlyArray<RadioOption>, selectedValue: string | undefined): number => {\n if (selectedValue === undefined) {\n return 0;\n }\n\n const index = options.findIndex((option) => option.value === selectedValue);\n\n return Math.max(index, 0);\n};\n\n/**\n * Single-choice radio group with keyboard navigation. By default, navigation\n * commits selection; set `commitOnNavigate={false}` to require an explicit\n * Space/Enter commit.\n */\nexport default function RadioGroup({\n accentColor = \"blue\",\n autoFocus = false,\n commitOnNavigate = true,\n defaultValue,\n isDisabled = false,\n onChange,\n onSubmit,\n options,\n orientation = \"vertical\",\n value,\n}: Props): ReactElement {\n const { isFocused } = useFocus({ autoFocus, isActive: !isDisabled });\n const [internal, setInternal] = useState(defaultValue ?? options[0]?.value);\n const current = value ?? internal;\n const [focusedIndex, setFocusedIndex] = useState<number>(() => initialFocusIndex(options, current));\n const focusedIndexRef = useRef(focusedIndex);\n\n focusedIndexRef.current = focusedIndex;\n\n const commit = useCallback(\n (index: number) => {\n const target = options[index];\n\n if (!target) {\n return;\n }\n\n const currentValue = value ?? internal;\n\n if (target.value === currentValue) {\n return;\n }\n\n if (value === undefined) {\n setInternal(target.value);\n }\n\n onChange?.(target.value);\n },\n [options, value, internal, onChange],\n );\n\n useInput(\n useCallback(\n (input, key) => {\n if (!isFocused) {\n return;\n }\n\n const total = options.length;\n\n if (total === 0) {\n return;\n }\n\n const moveNext = (key.downArrow && orientation === \"vertical\") || (key.rightArrow && orientation === \"horizontal\") || input === \"j\";\n const movePrevious = (key.upArrow && orientation === \"vertical\") || (key.leftArrow && orientation === \"horizontal\") || input === \"k\";\n\n if (moveNext) {\n const nextIndex = Math.min(total - 1, focusedIndexRef.current + 1);\n\n setFocusedIndex(nextIndex);\n\n if (commitOnNavigate) {\n commit(nextIndex);\n }\n\n return;\n }\n\n if (movePrevious) {\n const nextIndex = Math.max(0, focusedIndexRef.current - 1);\n\n setFocusedIndex(nextIndex);\n\n if (commitOnNavigate) {\n commit(nextIndex);\n }\n\n return;\n }\n\n if (input === \" \") {\n commit(focusedIndexRef.current);\n\n return;\n }\n\n if (key.return) {\n // Commit the focused option, then emit onSubmit with the new value.\n if (!commitOnNavigate) {\n commit(focusedIndexRef.current);\n }\n\n const submitValue = options[focusedIndexRef.current]?.value ?? current;\n\n if (submitValue !== undefined) {\n onSubmit?.(submitValue);\n }\n }\n },\n [isFocused, options, orientation, commit, commitOnNavigate, current, onSubmit],\n ),\n { isActive: !isDisabled && isFocused },\n );\n\n return (\n <Box flexDirection={orientation === \"vertical\" ? \"column\" : \"row\"} gap={orientation === \"vertical\" ? 0 : 2}>\n {options.map((option, index) => {\n const isSelected = option.value === current;\n const isItemFocused = isFocused && index === focusedIndex;\n const color = (isSelected || isItemFocused) && isFocused ? accentColor : undefined;\n\n return (\n <Box gap={1} key={option.key ?? option.value}>\n <Text color={color} dimColor={isDisabled}>\n {isSelected ? \"●\" : \"○\"}\n </Text>\n <Text bold={isItemFocused} color={color} dimColor={isDisabled}>\n {option.label}\n </Text>\n {option.description === undefined ? undefined : <Text dimColor>{option.description}</Text>}\n </Box>\n );\n })}\n </Box>\n );\n}\n\nexport { RadioGroup };\nexport type { Props as RadioGroupProps };\n",
|
|
19
|
+
"path": "registry/ui/radio-group.tsx",
|
|
20
|
+
"target": "components/ui/radio-group.tsx",
|
|
21
|
+
"type": "registry:ui"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|