@keyfunc/keybricks-ds 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DEPLOY.md +204 -0
- package/DESIGN.md +269 -0
- package/INTEGRATION.md +417 -0
- package/SKILL.md +32 -0
- package/_adherence.oxlintrc.json +1469 -0
- package/_scripts/build-index.mjs +80 -0
- package/_scripts/build-tokens.mjs +135 -0
- package/assets/icons/icon-index.js +1 -0
- package/assets/icons/icon-index.json +1 -0
- package/assets/icons/unicons-index.js +1 -0
- package/assets/icons/unicons-index.json +1 -0
- package/assets/keybricks-logo.png +0 -0
- package/components/_cards/accordion.card.html +32 -0
- package/components/_cards/action-chip.card.html +22 -0
- package/components/_cards/activity.card.html +34 -0
- package/components/_cards/alert.card.html +32 -0
- package/components/_cards/app-chrome.card.html +36 -0
- package/components/_cards/banner.card.html +21 -0
- package/components/_cards/brand-visual.card.html +43 -0
- package/components/_cards/breadcrumb.card.html +23 -0
- package/components/_cards/button-1-base.card.html +39 -0
- package/components/_cards/button-2-states.card.html +56 -0
- package/components/_cards/button-3-sizes-icons.card.html +32 -0
- package/components/_cards/button-4-group.card.html +47 -0
- package/components/_cards/canvas-zoom-controls.card.html +19 -0
- package/components/_cards/cards-indicators.card.html +59 -0
- package/components/_cards/charts-1-sparkline.card.html +55 -0
- package/components/_cards/charts-10-gauge.card.html +31 -0
- package/components/_cards/charts-11-funnel.card.html +28 -0
- package/components/_cards/charts-12-treemap.card.html +23 -0
- package/components/_cards/charts-14-radar.card.html +31 -0
- package/components/_cards/charts-15-distribution.card.html +32 -0
- package/components/_cards/charts-16-pareto.card.html +25 -0
- package/components/_cards/charts-17-candlestick.card.html +34 -0
- package/components/_cards/charts-18-sankey.card.html +29 -0
- package/components/_cards/charts-19-chord.card.html +31 -0
- package/components/_cards/charts-2-line.card.html +46 -0
- package/components/_cards/charts-20-sunburst.card.html +38 -0
- package/components/_cards/charts-21-worldmap.card.html +33 -0
- package/components/_cards/charts-22-gantt.card.html +37 -0
- package/components/_cards/charts-23-bar3d.card.html +26 -0
- package/components/_cards/charts-24-pie3d.card.html +32 -0
- package/components/_cards/charts-25-surface3d.card.html +24 -0
- package/components/_cards/charts-26-scatter3d.card.html +24 -0
- package/components/_cards/charts-27-ribbon3d.card.html +23 -0
- package/components/_cards/charts-3-bar.card.html +71 -0
- package/components/_cards/charts-4-barlist.card.html +30 -0
- package/components/_cards/charts-5-donut.card.html +35 -0
- package/components/_cards/charts-6-scatter.card.html +26 -0
- package/components/_cards/charts-7-heatmap.card.html +28 -0
- package/components/_cards/charts-8-waterfall.card.html +25 -0
- package/components/_cards/charts-9-bullet.card.html +31 -0
- package/components/_cards/charts-99-fullpage.card.html +194 -0
- package/components/_cards/checkbox.card.html +34 -0
- package/components/_cards/codeblock.card.html +19 -0
- package/components/_cards/combobox.card.html +25 -0
- package/components/_cards/context-menu.card.html +21 -0
- package/components/_cards/datatable.card.html +48 -0
- package/components/_cards/date-picker.card.html +31 -0
- package/components/_cards/diffvalue.card.html +21 -0
- package/components/_cards/divider.card.html +24 -0
- package/components/_cards/drawer.card.html +30 -0
- package/components/_cards/dropdown-menu.card.html +38 -0
- package/components/_cards/dropzone.card.html +22 -0
- package/components/_cards/empty-state.card.html +29 -0
- package/components/_cards/filter-bar.card.html +34 -0
- package/components/_cards/icon-button.card.html +27 -0
- package/components/_cards/icons-1-core.card.html +49 -0
- package/components/_cards/icons-2-feather.card.html +39 -0
- package/components/_cards/icons-3-unicons.card.html +44 -0
- package/components/_cards/input.card.html +25 -0
- package/components/_cards/kbd.card.html +20 -0
- package/components/_cards/keyvalue.card.html +23 -0
- package/components/_cards/listrow.card.html +30 -0
- package/components/_cards/loading.card.html +33 -0
- package/components/_cards/log-viewer.card.html +23 -0
- package/components/_cards/modal.card.html +35 -0
- package/components/_cards/multi-select.card.html +26 -0
- package/components/_cards/number-stepper.card.html +24 -0
- package/components/_cards/pagination.card.html +25 -0
- package/components/_cards/people.card.html +46 -0
- package/components/_cards/pipeline-node.card.html +76 -0
- package/components/_cards/pipeline-palette.card.html +54 -0
- package/components/_cards/search.card.html +23 -0
- package/components/_cards/select.card.html +23 -0
- package/components/_cards/slider.card.html +25 -0
- package/components/_cards/smart-table.card.html +37 -0
- package/components/_cards/spreadsheet.card.html +31 -0
- package/components/_cards/stepper.card.html +25 -0
- package/components/_cards/tabs.card.html +25 -0
- package/components/_cards/tag.card.html +26 -0
- package/components/_cards/textarea.card.html +27 -0
- package/components/_cards/timeline.card.html +32 -0
- package/components/_cards/toast.card.html +33 -0
- package/components/_cards/toggles.card.html +68 -0
- package/components/_cards/tooltip.card.html +22 -0
- package/components/_cards/tree.card.html +150 -0
- package/components/_shared/frame-theme.js +16 -0
- package/components/_shared/src-brand.js +1 -0
- package/components/_shared/src-buttons.js +1 -0
- package/components/_shared/src-charts.js +1 -0
- package/components/_shared/src-data.js +1 -0
- package/components/_shared/src-display.js +1 -0
- package/components/_shared/src-feedback.js +1 -0
- package/components/_shared/src-forms.js +1 -0
- package/components/_shared/src-icons.js +1 -0
- package/components/_shared/src-navigation.js +1 -0
- package/components/_shared/src-pipeline.js +1 -0
- package/components/_shared/src-tabs.js +1 -0
- package/components/_shared/svg-download.js +19 -0
- package/components/_shared/view-source.js +185 -0
- package/components/_vue/index.mjs +114 -0
- package/components/brand/BrandVisual.d.ts +17 -0
- package/components/brand/BrandVisual.jsx +29 -0
- package/components/brand/BrandVisual.vue +34 -0
- package/components/brand/_dir.card.html +13 -0
- package/components/brand/brandMotifs.js +210 -0
- package/components/buttons/ActionChip.d.ts +10 -0
- package/components/buttons/ActionChip.jsx +20 -0
- package/components/buttons/ActionChip.vue +18 -0
- package/components/buttons/Button.d.ts +40 -0
- package/components/buttons/Button.jsx +101 -0
- package/components/buttons/Button.vue +87 -0
- package/components/buttons/IconButton.d.ts +26 -0
- package/components/buttons/IconButton.jsx +28 -0
- package/components/buttons/IconButton.vue +21 -0
- package/components/buttons/_dir.card.html +13 -0
- package/components/buttons/buttons.prompt.md +19 -0
- package/components/charts/Bar3D.d.ts +15 -0
- package/components/charts/Bar3D.jsx +93 -0
- package/components/charts/Bar3D.vue +79 -0
- package/components/charts/BarChart.d.ts +23 -0
- package/components/charts/BarChart.jsx +135 -0
- package/components/charts/BarChart.vue +139 -0
- package/components/charts/BarList.d.ts +13 -0
- package/components/charts/BarList.jsx +31 -0
- package/components/charts/BarList.vue +25 -0
- package/components/charts/BoxPlot.d.ts +18 -0
- package/components/charts/BoxPlot.jsx +62 -0
- package/components/charts/BoxPlot.vue +58 -0
- package/components/charts/BulletChart.d.ts +12 -0
- package/components/charts/BulletChart.jsx +41 -0
- package/components/charts/BulletChart.vue +33 -0
- package/components/charts/CandlestickChart.d.ts +15 -0
- package/components/charts/CandlestickChart.jsx +63 -0
- package/components/charts/CandlestickChart.vue +62 -0
- package/components/charts/ChartKit.d.ts +8 -0
- package/components/charts/ChartKit.jsx +76 -0
- package/components/charts/ChartKit.vue +47 -0
- package/components/charts/ChordChart.d.ts +13 -0
- package/components/charts/ChordChart.jsx +55 -0
- package/components/charts/ChordChart.vue +54 -0
- package/components/charts/DonutChart.d.ts +15 -0
- package/components/charts/DonutChart.jsx +73 -0
- package/components/charts/DonutChart.vue +61 -0
- package/components/charts/FunnelChart.d.ts +11 -0
- package/components/charts/FunnelChart.jsx +37 -0
- package/components/charts/FunnelChart.vue +29 -0
- package/components/charts/GanttChart.d.ts +20 -0
- package/components/charts/GanttChart.jsx +80 -0
- package/components/charts/GanttChart.vue +60 -0
- package/components/charts/GaugeChart.d.ts +13 -0
- package/components/charts/GaugeChart.jsx +33 -0
- package/components/charts/GaugeChart.vue +29 -0
- package/components/charts/HeatmapChart.d.ts +13 -0
- package/components/charts/HeatmapChart.jsx +62 -0
- package/components/charts/HeatmapChart.vue +38 -0
- package/components/charts/Histogram.d.ts +16 -0
- package/components/charts/Histogram.jsx +56 -0
- package/components/charts/Histogram.vue +53 -0
- package/components/charts/LineChart.d.ts +17 -0
- package/components/charts/LineChart.jsx +84 -0
- package/components/charts/LineChart.vue +86 -0
- package/components/charts/ParetoChart.d.ts +13 -0
- package/components/charts/ParetoChart.jsx +54 -0
- package/components/charts/ParetoChart.vue +55 -0
- package/components/charts/Pie3D.d.ts +17 -0
- package/components/charts/Pie3D.jsx +145 -0
- package/components/charts/Pie3D.vue +115 -0
- package/components/charts/RadarChart.d.ts +14 -0
- package/components/charts/RadarChart.jsx +79 -0
- package/components/charts/RadarChart.vue +73 -0
- package/components/charts/Ribbon3D.d.ts +13 -0
- package/components/charts/Ribbon3D.jsx +89 -0
- package/components/charts/Ribbon3D.vue +79 -0
- package/components/charts/SankeyChart.d.ts +15 -0
- package/components/charts/SankeyChart.jsx +59 -0
- package/components/charts/SankeyChart.vue +53 -0
- package/components/charts/Scatter3D.d.ts +12 -0
- package/components/charts/Scatter3D.jsx +69 -0
- package/components/charts/Scatter3D.vue +59 -0
- package/components/charts/ScatterChart.d.ts +12 -0
- package/components/charts/ScatterChart.jsx +53 -0
- package/components/charts/ScatterChart.vue +57 -0
- package/components/charts/Sparkline.d.ts +19 -0
- package/components/charts/Sparkline.jsx +63 -0
- package/components/charts/Sparkline.vue +54 -0
- package/components/charts/SunburstChart.d.ts +12 -0
- package/components/charts/SunburstChart.jsx +61 -0
- package/components/charts/SunburstChart.vue +60 -0
- package/components/charts/Surface3D.d.ts +13 -0
- package/components/charts/Surface3D.jsx +70 -0
- package/components/charts/Surface3D.vue +63 -0
- package/components/charts/TreemapChart.d.ts +11 -0
- package/components/charts/TreemapChart.jsx +35 -0
- package/components/charts/TreemapChart.vue +27 -0
- package/components/charts/WaterfallChart.d.ts +11 -0
- package/components/charts/WaterfallChart.jsx +59 -0
- package/components/charts/WaterfallChart.vue +46 -0
- package/components/charts/WorldMap.d.ts +21 -0
- package/components/charts/WorldMap.jsx +107 -0
- package/components/charts/WorldMap.vue +73 -0
- package/components/charts/_dir.card.html +7 -0
- package/components/charts/chart-3d.js +84 -0
- package/components/charts/chart-geometry.js +223 -0
- package/components/charts/charts.prompt.md +24 -0
- package/components/data/CodeBlock.d.ts +9 -0
- package/components/data/CodeBlock.jsx +19 -0
- package/components/data/CodeBlock.vue +22 -0
- package/components/data/DataTable.d.ts +28 -0
- package/components/data/DataTable.jsx +32 -0
- package/components/data/DataTable.vue +25 -0
- package/components/data/DiffValue.d.ts +11 -0
- package/components/data/DiffValue.jsx +15 -0
- package/components/data/DiffValue.vue +13 -0
- package/components/data/FilterBar.d.ts +16 -0
- package/components/data/FilterBar.jsx +22 -0
- package/components/data/FilterBar.vue +23 -0
- package/components/data/KeyValue.d.ts +16 -0
- package/components/data/KeyValue.jsx +25 -0
- package/components/data/KeyValue.vue +26 -0
- package/components/data/ListRow.d.ts +14 -0
- package/components/data/ListRow.jsx +25 -0
- package/components/data/ListRow.vue +25 -0
- package/components/data/Pagination.d.ts +12 -0
- package/components/data/Pagination.jsx +27 -0
- package/components/data/Pagination.vue +24 -0
- package/components/data/SmartTable.d.ts +30 -0
- package/components/data/SmartTable.jsx +73 -0
- package/components/data/SmartTable.vue +74 -0
- package/components/data/Spreadsheet.d.ts +33 -0
- package/components/data/Spreadsheet.jsx +110 -0
- package/components/data/Spreadsheet.vue +95 -0
- package/components/data/_dir.card.html +13 -0
- package/components/data/data.prompt.md +33 -0
- package/components/display/Avatar.d.ts +21 -0
- package/components/display/Avatar.jsx +31 -0
- package/components/display/Avatar.vue +34 -0
- package/components/display/Badge.d.ts +27 -0
- package/components/display/Badge.jsx +40 -0
- package/components/display/Badge.vue +47 -0
- package/components/display/Card.d.ts +27 -0
- package/components/display/Card.jsx +27 -0
- package/components/display/Card.vue +28 -0
- package/components/display/Divider.d.ts +8 -0
- package/components/display/Divider.jsx +14 -0
- package/components/display/Divider.vue +13 -0
- package/components/display/Kbd.d.ts +7 -0
- package/components/display/Kbd.jsx +12 -0
- package/components/display/Kbd.vue +9 -0
- package/components/display/ProgressBar.d.ts +42 -0
- package/components/display/ProgressBar.jsx +70 -0
- package/components/display/ProgressBar.vue +69 -0
- package/components/display/Tag.d.ts +9 -0
- package/components/display/Tag.jsx +15 -0
- package/components/display/Tag.vue +15 -0
- package/components/display/_dir.card.html +13 -0
- package/components/display/display.prompt.md +30 -0
- package/components/feedback/Accordion.d.ts +13 -0
- package/components/feedback/Accordion.jsx +21 -0
- package/components/feedback/Accordion.vue +22 -0
- package/components/feedback/ActivityItem.d.ts +25 -0
- package/components/feedback/ActivityItem.jsx +39 -0
- package/components/feedback/ActivityItem.vue +46 -0
- package/components/feedback/Alert.d.ts +36 -0
- package/components/feedback/Alert.jsx +48 -0
- package/components/feedback/Alert.vue +59 -0
- package/components/feedback/Banner.d.ts +15 -0
- package/components/feedback/Banner.jsx +25 -0
- package/components/feedback/Banner.vue +25 -0
- package/components/feedback/ContextMenu.d.ts +8 -0
- package/components/feedback/ContextMenu.jsx +18 -0
- package/components/feedback/ContextMenu.vue +19 -0
- package/components/feedback/Drawer.d.ts +18 -0
- package/components/feedback/Drawer.jsx +26 -0
- package/components/feedback/Drawer.vue +24 -0
- package/components/feedback/Menu.d.ts +10 -0
- package/components/feedback/Menu.jsx +24 -0
- package/components/feedback/Menu.vue +21 -0
- package/components/feedback/Modal.d.ts +38 -0
- package/components/feedback/Modal.jsx +69 -0
- package/components/feedback/Modal.vue +65 -0
- package/components/feedback/Stepper.d.ts +9 -0
- package/components/feedback/Stepper.jsx +24 -0
- package/components/feedback/Stepper.vue +18 -0
- package/components/feedback/Timeline.d.ts +15 -0
- package/components/feedback/Timeline.jsx +27 -0
- package/components/feedback/Timeline.vue +21 -0
- package/components/feedback/_dir.card.html +13 -0
- package/components/feedback/feedback.prompt.md +35 -0
- package/components/forms/Checkbox.d.ts +13 -0
- package/components/forms/Checkbox.jsx +17 -0
- package/components/forms/Checkbox.vue +18 -0
- package/components/forms/Combobox.d.ts +13 -0
- package/components/forms/Combobox.jsx +34 -0
- package/components/forms/Combobox.vue +35 -0
- package/components/forms/DatePicker.d.ts +12 -0
- package/components/forms/DatePicker.jsx +48 -0
- package/components/forms/DatePicker.vue +46 -0
- package/components/forms/Dropzone.d.ts +20 -0
- package/components/forms/Dropzone.jsx +36 -0
- package/components/forms/Dropzone.vue +28 -0
- package/components/forms/Field.d.ts +13 -0
- package/components/forms/Field.jsx +13 -0
- package/components/forms/Field.vue +12 -0
- package/components/forms/Input.d.ts +18 -0
- package/components/forms/Input.jsx +35 -0
- package/components/forms/Input.vue +38 -0
- package/components/forms/MultiSelect.d.ts +14 -0
- package/components/forms/MultiSelect.jsx +33 -0
- package/components/forms/MultiSelect.vue +36 -0
- package/components/forms/NumberStepper.d.ts +13 -0
- package/components/forms/NumberStepper.jsx +15 -0
- package/components/forms/NumberStepper.vue +17 -0
- package/components/forms/Radio.vue +16 -0
- package/components/forms/RadioGroup.vue +11 -0
- package/components/forms/SearchInput.d.ts +12 -0
- package/components/forms/SearchInput.jsx +17 -0
- package/components/forms/SearchInput.vue +14 -0
- package/components/forms/Select.d.ts +14 -0
- package/components/forms/Select.jsx +17 -0
- package/components/forms/Select.vue +16 -0
- package/components/forms/Slider.d.ts +15 -0
- package/components/forms/Slider.jsx +21 -0
- package/components/forms/Slider.vue +23 -0
- package/components/forms/Switch.d.ts +31 -0
- package/components/forms/Switch.jsx +40 -0
- package/components/forms/Switch.vue +16 -0
- package/components/forms/_dir.card.html +13 -0
- package/components/forms/forms.prompt.md +23 -0
- package/components/icons/Icon.d.ts +19 -0
- package/components/icons/Icon.jsx +93 -0
- package/components/icons/Icon.prompt.md +8 -0
- package/components/icons/Icon.vue +12 -0
- package/components/icons/Unicon.d.ts +12 -0
- package/components/icons/Unicon.jsx +16 -0
- package/components/icons/Unicon.vue +15 -0
- package/components/icons/_dir.card.html +13 -0
- package/components/icons/feather-paths.js +2 -0
- package/components/icons/icon-paths.js +73 -0
- package/components/index.d.ts +87 -0
- package/components/index.js +110 -0
- package/components/navigation/Breadcrumb.d.ts +24 -0
- package/components/navigation/Breadcrumb.jsx +120 -0
- package/components/navigation/Breadcrumb.vue +94 -0
- package/components/navigation/DocTree.d.ts +18 -0
- package/components/navigation/DocTree.jsx +37 -0
- package/components/navigation/DocTree.vue +25 -0
- package/components/navigation/Sidebar.d.ts +29 -0
- package/components/navigation/Sidebar.jsx +75 -0
- package/components/navigation/Sidebar.vue +54 -0
- package/components/navigation/TopBar.d.ts +27 -0
- package/components/navigation/TopBar.jsx +44 -0
- package/components/navigation/TopBar.vue +51 -0
- package/components/navigation/Tree.d.ts +83 -0
- package/components/navigation/Tree.jsx +347 -0
- package/components/navigation/Tree.vue +258 -0
- package/components/navigation/_dir.card.html +13 -0
- package/components/navigation/navigation.prompt.md +22 -0
- package/components/pipeline/ConfigPanel.d.ts +18 -0
- package/components/pipeline/ConfigPanel.jsx +30 -0
- package/components/pipeline/ConfigPanel.vue +32 -0
- package/components/pipeline/DataPreview.d.ts +14 -0
- package/components/pipeline/DataPreview.jsx +24 -0
- package/components/pipeline/DataPreview.vue +21 -0
- package/components/pipeline/NodeCard.d.ts +47 -0
- package/components/pipeline/NodeCard.jsx +97 -0
- package/components/pipeline/NodeCard.vue +75 -0
- package/components/pipeline/PaletteItem.vue +15 -0
- package/components/pipeline/PaletteListItem.vue +15 -0
- package/components/pipeline/PalettePanel.d.ts +20 -0
- package/components/pipeline/PalettePanel.jsx +74 -0
- package/components/pipeline/PalettePanel.vue +45 -0
- package/components/pipeline/PipelineCanvas.d.ts +25 -0
- package/components/pipeline/PipelineCanvas.jsx +94 -0
- package/components/pipeline/PipelineCanvas.vue +73 -0
- package/components/pipeline/ZoomControls.d.ts +9 -0
- package/components/pipeline/ZoomControls.jsx +15 -0
- package/components/pipeline/ZoomControls.vue +15 -0
- package/components/pipeline/_dir.card.html +13 -0
- package/components/pipeline/pipeline.prompt.md +22 -0
- package/components/tabs/SegmentedControl.d.ts +11 -0
- package/components/tabs/SegmentedControl.jsx +21 -0
- package/components/tabs/SegmentedControl.vue +15 -0
- package/components/tabs/Tabs.d.ts +13 -0
- package/components/tabs/Tabs.jsx +52 -0
- package/components/tabs/Tabs.vue +39 -0
- package/components/tabs/ViewToggle.d.ts +8 -0
- package/components/tabs/ViewToggle.jsx +12 -0
- package/components/tabs/ViewToggle.vue +12 -0
- package/components/tabs/_dir.card.html +13 -0
- package/components/tabs/tabs.prompt.md +14 -0
- package/package.json +76 -0
- package/readme.md +150 -0
- package/styles.css +10 -0
- package/tokens/alpha.css +27 -0
- package/tokens/charts.css +55 -0
- package/tokens/colors-extended.css +40 -0
- package/tokens/colors.css +39 -0
- package/tokens/dark.css +96 -0
- package/tokens/fonts.css +4 -0
- package/tokens/interaction.css +48 -0
- package/tokens/layout.css +30 -0
- package/tokens/motion.css +22 -0
- package/tokens/tokens.d.ts +680 -0
- package/tokens/tokens.js +1018 -0
- package/tokens/tokens.json +2928 -0
- package/tokens/typography.css +22 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import Icon from '../icons/Icon.vue'
|
|
4
|
+
const tones = { neutral: { bg: 'var(--bg-hover)', fg: 'var(--text-body)' }, info: { bg: 'var(--info-bg)', fg: 'var(--info-fg)' } }
|
|
5
|
+
// Small removable filter tag — distinct from Badge (status) and ActionChip (bulk action).
|
|
6
|
+
const props = defineProps({ tone: { type: String, default: 'neutral' }, removable: Boolean, style: Object })
|
|
7
|
+
defineEmits(['remove'])
|
|
8
|
+
const t = computed(() => tones[props.tone] || tones.neutral)
|
|
9
|
+
</script>
|
|
10
|
+
<template>
|
|
11
|
+
<span :style="{ display: 'inline-flex', alignItems: 'center', gap: 4, height: 22, padding: removable ? '0 6px 0 10px' : '0 10px', borderRadius: 'var(--radius-full)', background: t.bg, color: t.fg, fontFamily: 'var(--font-sans)', fontSize: 'var(--text-xs)', fontWeight: 'var(--weight-medium)', letterSpacing: 'var(--tracking-xs)', ...style }">
|
|
12
|
+
<slot />
|
|
13
|
+
<button v-if="removable" type="button" @click="$emit('remove')" style="border:none;background:transparent;cursor:pointer;color:inherit;opacity:.7;display:flex;padding:0"><Icon name="x" :size="11" /></button>
|
|
14
|
+
</span>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!-- @dsCard group="Directory Index" viewport="700x90" name="Display dir" subtitle="Full cards: Components → Cards & Indicators / Tag / etc." -->
|
|
2
|
+
<!DOCTYPE html>
|
|
3
|
+
<html><head><meta charset="utf-8"><link rel="stylesheet" href="../../styles.css">
|
|
4
|
+
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
|
|
5
|
+
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
|
|
6
|
+
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
7
|
+
<script src="../../_ds_bundle.js"></script>
|
|
8
|
+
<style>body{margin:0;background:var(--bg-surface);padding:16px;font-family:var(--font-sans)}</style></head>
|
|
9
|
+
<body><div id="root"></div>
|
|
10
|
+
<script type="text/babel">
|
|
11
|
+
const { Card } = window.KeybricksDesignSystem_71231a;
|
|
12
|
+
ReactDOM.createRoot(document.getElementById("root")).render(<Card title="Revenue Trend" style={{width:220}}><span style={{fontSize:12,color:"var(--text-secondary)"}}>See Components tab for full states</span></Card>);
|
|
13
|
+
</script></body></html>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
**Work in progress**: `Card` layout/spacing is still being refined against the redesigned specimen — check `display.card.html` for the current reference before building new screens on it.
|
|
2
|
+
|
|
3
|
+
Surfaces & indicators: `Card`/`StatCard`, `Badge` (tinted pill), `StatusBadge` (solid dot + white ring), `IconTile` (tinted category square), `ProgressBar`, `Donut`, `AreaChart`, `MiniBars`.
|
|
4
|
+
|
|
5
|
+
```jsx
|
|
6
|
+
<Card title="Revenue Trend"><AreaChart/></Card>
|
|
7
|
+
<StatCard label="Total Tasks" value="156"><MiniBars/></StatCard>
|
|
8
|
+
<ProgressBar label="Operations" value={45}/>
|
|
9
|
+
<Donut value={75}/>
|
|
10
|
+
<Badge tone="success">Completed</Badge>
|
|
11
|
+
<StatusBadge tone="danger" icon="bug" size={20}/>
|
|
12
|
+
<IconTile icon="table" hue="source" kind="node"/>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Cards are flat (no shadow). IconTile hues: source green, join blue, transform orange, merge purple, output teal.
|
|
16
|
+
|
|
17
|
+
`Avatar` / `AvatarGroup` (additions) — the source has no avatar imagery, so people render as tinted initials; pass `src` only when you have a real image.
|
|
18
|
+
|
|
19
|
+
```jsx
|
|
20
|
+
<Avatar name="Felix Chen" size={30}/>
|
|
21
|
+
<AvatarGroup names={["Felix Chen","Mia Park","Chen Wu","Ana Diaz","Sam Lee"]}/>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`Tag`, `Divider`, `Kbd` (additions) — small primitives that formalize patterns used ad hoc throughout the UI kit:
|
|
25
|
+
|
|
26
|
+
```jsx
|
|
27
|
+
<Tag onRemove={remove}>Financial Settings</Tag>
|
|
28
|
+
<Divider label="OR"/> <Divider vertical/>
|
|
29
|
+
<Kbd keys={["⌘","K"]}/>
|
|
30
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/** Generic collapsible section (chevron + title/subtitle + body). Addition — distinct from ListRow (which is workflow-doc specific). */
|
|
3
|
+
export interface AccordionProps {
|
|
4
|
+
title?: React.ReactNode;
|
|
5
|
+
subtitle?: React.ReactNode;
|
|
6
|
+
defaultOpen?: boolean;
|
|
7
|
+
/** Controlled state */
|
|
8
|
+
open?: boolean;
|
|
9
|
+
onToggle?: (next: boolean) => void;
|
|
10
|
+
children?: React.ReactNode;
|
|
11
|
+
style?: React.CSSProperties;
|
|
12
|
+
}
|
|
13
|
+
export declare function Accordion(props: AccordionProps): JSX.Element;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Icon } from "../icons/Icon.jsx";
|
|
3
|
+
|
|
4
|
+
/** Generic collapsible section: chevron + title/subtitle header, body slot. Controlled via `open`+`onToggle`, or uncontrolled via `defaultOpen`. */
|
|
5
|
+
export function Accordion({ title, subtitle, defaultOpen, open: openProp, onToggle, children, style }) {
|
|
6
|
+
const [openState, setOpenState] = React.useState(!!defaultOpen);
|
|
7
|
+
const open = openProp != null ? openProp : openState;
|
|
8
|
+
const toggle = () => (onToggle ? onToggle(!open) : setOpenState(!open));
|
|
9
|
+
return (
|
|
10
|
+
<div style={{ borderBottom: "1px solid var(--border-card)", ...style }}>
|
|
11
|
+
<div onClick={toggle} style={{ display: "flex", alignItems: "center", gap: 10, padding: "14px 4px", cursor: "pointer" }}>
|
|
12
|
+
<span style={{ color: "var(--text-muted)", display: "inline-flex", transform: open ? "rotate(90deg)" : "none", transition: "transform var(--dur-fast) var(--ease-out)" }}><Icon name="chevron-right" size={14} /></span>
|
|
13
|
+
<div style={{ display: "flex", flexDirection: "column", flex: 1 }}>
|
|
14
|
+
<span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-base)", letterSpacing: "var(--tracking-base)", color: "var(--text-heading)" }}>{title}</span>
|
|
15
|
+
{subtitle ? <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-sm)", color: "var(--text-secondary)" }}>{subtitle}</span> : null}
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
{open ? <div style={{ padding: "0 4px 16px 28px" }}>{children}</div> : null}
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, computed } from 'vue'
|
|
3
|
+
import Icon from '../icons/Icon.vue'
|
|
4
|
+
// Generic collapsible section: chevron + title/subtitle header, body slot. Controlled via `open` prop + `toggle` emit, or uncontrolled via `defaultOpen`.
|
|
5
|
+
const props = defineProps({ title: String, subtitle: String, defaultOpen: Boolean, open: { type: Boolean, default: null }, style: Object })
|
|
6
|
+
const emit = defineEmits(['toggle'])
|
|
7
|
+
const openState = ref(!!props.defaultOpen)
|
|
8
|
+
const open = computed(() => props.open != null ? props.open : openState.value)
|
|
9
|
+
function toggle() { if (props.open != null) emit('toggle', !open.value); else openState.value = !openState.value }
|
|
10
|
+
</script>
|
|
11
|
+
<template>
|
|
12
|
+
<div :style="{ borderBottom: '1px solid var(--border-card)', ...style }">
|
|
13
|
+
<div @click="toggle" style="display:flex;align-items:center;gap:10px;padding:14px 4px;cursor:pointer">
|
|
14
|
+
<span :style="{ color: 'var(--text-muted)', display: 'inline-flex', transform: open ? 'rotate(90deg)' : 'none', transition: 'transform var(--dur-fast) var(--ease-out)' }"><Icon name="chevron-right" :size="14" /></span>
|
|
15
|
+
<div style="display:flex;flex-direction:column;flex:1">
|
|
16
|
+
<span style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-base);letter-spacing:var(--tracking-base);color:var(--text-heading)">{{ title }}</span>
|
|
17
|
+
<span v-if="subtitle" style="font-family:var(--font-sans);font-size:var(--text-sm);color:var(--text-secondary)">{{ subtitle }}</span>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<div v-if="open" style="padding:0 4px 16px 28px"><slot /></div>
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/** Feed row: 32px blue-tint icon tile, 13px/500 title, 12px meta, right action text ("Open"). */
|
|
3
|
+
export interface ActivityItemProps {
|
|
4
|
+
icon?: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
meta?: string;
|
|
7
|
+
action?: React.ReactNode;
|
|
8
|
+
style?: React.CSSProperties;
|
|
9
|
+
}
|
|
10
|
+
export declare function ActivityItem(props: ActivityItemProps): JSX.Element;
|
|
11
|
+
/** Compact 8px-dot activity row for dense cards. */
|
|
12
|
+
export interface DotActivityProps {
|
|
13
|
+
tone?: "success" | "warning" | "danger" | "info" | "neutral";
|
|
14
|
+
text?: string;
|
|
15
|
+
time?: string;
|
|
16
|
+
style?: React.CSSProperties;
|
|
17
|
+
}
|
|
18
|
+
export declare function DotActivity(props: DotActivityProps): JSX.Element;
|
|
19
|
+
/** Menlo 11px log panel. lines: string | {text, color}. */
|
|
20
|
+
export interface LogViewerProps {
|
|
21
|
+
lines?: (string | { text: string; color?: string })[];
|
|
22
|
+
height?: number | string;
|
|
23
|
+
style?: React.CSSProperties;
|
|
24
|
+
}
|
|
25
|
+
export declare function LogViewer(props: LogViewerProps): JSX.Element;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { IconTile } from "../display/Badge.jsx";
|
|
3
|
+
|
|
4
|
+
/** Activity feed row: 32px icon tile + 13px/500 title + 12px meta + optional right action. */
|
|
5
|
+
export function ActivityItem({ icon = "file-text", title, meta, action, style }) {
|
|
6
|
+
return (
|
|
7
|
+
<div style={{ display: "flex", alignItems: "center", gap: 12, padding: "12px 16px", ...style }}>
|
|
8
|
+
<IconTile icon={icon} kind="row" style={{ background: "var(--info-bg)", border: "none", color: "var(--info-fg)" }} />
|
|
9
|
+
<div style={{ display: "flex", flexDirection: "column", flex: 1, minWidth: 0 }}>
|
|
10
|
+
<span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-base)", lineHeight: "var(--leading-base)", letterSpacing: "var(--tracking-base)", color: "var(--text-heading)" }}>{title}</span>
|
|
11
|
+
{meta ? <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-sm)", lineHeight: "var(--leading-sm)", color: "var(--text-secondary)" }}>{meta}</span> : null}
|
|
12
|
+
</div>
|
|
13
|
+
{action ? <span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-base)", letterSpacing: "var(--tracking-base)", color: "var(--text-secondary)", cursor: "pointer" }}>{action}</span> : null}
|
|
14
|
+
</div>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Compact dot activity row (Recent Activities card): 8px status dot + 12px text + 11px time. */
|
|
19
|
+
export function DotActivity({ tone = "success", text, time, style }) {
|
|
20
|
+
const tones = { success: "var(--success)", warning: "var(--warning)", danger: "var(--danger)", info: "var(--action-primary)", neutral: "var(--dot-neutral)" };
|
|
21
|
+
return (
|
|
22
|
+
<div style={{ display: "flex", gap: 8, alignItems: "flex-start", ...style }}>
|
|
23
|
+
<span style={{ width: 8, height: 8, borderRadius: "var(--radius-full)", background: tones[tone], marginTop: 5, flexShrink: 0 }} />
|
|
24
|
+
<div style={{ display: "flex", flexDirection: "column", minWidth: 0 }}>
|
|
25
|
+
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-sm)", lineHeight: "var(--leading-sm)", color: "var(--text-heading)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{text}</span>
|
|
26
|
+
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", lineHeight: "var(--leading-xs)", letterSpacing: "var(--tracking-xs)", color: "var(--text-muted)" }}>{time}</span>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Mono log lines ("[14:30] Task started: Import") — Menlo 11px on inset panel. */
|
|
33
|
+
export function LogViewer({ lines = [], height, style }) {
|
|
34
|
+
return (
|
|
35
|
+
<div style={{ background: "var(--bg-inset)", borderRadius: "var(--radius-md)", border: "1px solid var(--border-subtle)", padding: "10px 12px", display: "flex", flexDirection: "column", gap: 6, overflowY: "auto", height, boxSizing: "border-box", ...style }}>
|
|
36
|
+
{lines.map((l, i) => <span key={i} style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-xs)", lineHeight: "var(--leading-xs)", color: typeof l === "object" ? l.color || "var(--text-body)" : "var(--text-body)", whiteSpace: "pre" }}>{typeof l === "object" ? l.text : l}</span>)}
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { IconTile } from '../display/Badge.vue'
|
|
3
|
+
// Activity feed row: 32px icon tile + 13px/500 title + 12px meta + optional right action.
|
|
4
|
+
defineProps({ icon: { type: String, default: 'file-text' }, title: String, meta: String, action: String, style: Object })
|
|
5
|
+
</script>
|
|
6
|
+
<template>
|
|
7
|
+
<div :style="{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px 16px', ...style }">
|
|
8
|
+
<IconTile :icon="icon" kind="row" style="background:var(--info-bg);border:none;color:var(--info-fg)" />
|
|
9
|
+
<div style="display:flex;flex-direction:column;flex:1;min-width:0">
|
|
10
|
+
<span style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);color:var(--text-heading)">{{ title }}</span>
|
|
11
|
+
<span v-if="meta" style="font-family:var(--font-sans);font-size:var(--text-sm);line-height:var(--leading-sm);color:var(--text-secondary)">{{ meta }}</span>
|
|
12
|
+
</div>
|
|
13
|
+
<span v-if="action" style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-base);letter-spacing:var(--tracking-base);color:var(--text-secondary);cursor:pointer">{{ action }}</span>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<!-- DotActivity — compact dot activity row (Recent Activities card): 8px status dot + 12px text + 11px time. -->
|
|
18
|
+
<!--
|
|
19
|
+
<script setup name="DotActivity">
|
|
20
|
+
import { computed } from 'vue'
|
|
21
|
+
const tonesMap = { success: 'var(--success)', warning: 'var(--warning)', danger: 'var(--danger)', info: 'var(--action-primary)', neutral: 'var(--dot-neutral)' }
|
|
22
|
+
const props = defineProps({ tone: { type: String, default: 'success' }, text: String, time: String, style: Object })
|
|
23
|
+
const dot = computed(() => tonesMap[props.tone])
|
|
24
|
+
</script>
|
|
25
|
+
<template>
|
|
26
|
+
<div :style="{ display: 'flex', gap: 8, alignItems: 'flex-start', ...style }">
|
|
27
|
+
<span :style="{ width: 8, height: 8, borderRadius: 'var(--radius-full)', background: dot, marginTop: 5, flexShrink: 0 }" />
|
|
28
|
+
<div style="display:flex;flex-direction:column;min-width:0">
|
|
29
|
+
<span style="font-family:var(--font-sans);font-size:var(--text-sm);line-height:var(--leading-sm);color:var(--text-heading);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{{ text }}</span>
|
|
30
|
+
<span style="font-family:var(--font-sans);font-size:var(--text-xs);line-height:var(--leading-xs);letter-spacing:var(--tracking-xs);color:var(--text-muted)">{{ time }}</span>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
-->
|
|
35
|
+
|
|
36
|
+
<!-- LogViewer — mono log lines ("[14:30] Task started: Import") — Menlo 11px on inset panel. -->
|
|
37
|
+
<!--
|
|
38
|
+
<script setup name="LogViewer">
|
|
39
|
+
defineProps({ lines: { type: Array, default: () => [] }, height: [Number, String], style: Object })
|
|
40
|
+
</script>
|
|
41
|
+
<template>
|
|
42
|
+
<div :style="{ background: 'var(--bg-inset)', borderRadius: 'var(--radius-md)', border: '1px solid var(--border-subtle)', padding: '10px 12px', display: 'flex', flexDirection: 'column', gap: 6, overflowY: 'auto', height, boxSizing: 'border-box', ...style }">
|
|
43
|
+
<span v-for="(l, i) in lines" :key="i" :style="{ fontFamily: 'var(--font-mono)', fontSize: 'var(--text-xs)', lineHeight: 'var(--leading-xs)', color: typeof l === 'object' ? (l.color || 'var(--text-body)') : 'var(--text-body)', whiteSpace: 'pre' }">{{ typeof l === 'object' ? l.text : l }}</span>
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
46
|
+
-->
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/** Inline tinted banner. Addition — not in the source file. */
|
|
3
|
+
export interface AlertProps {
|
|
4
|
+
tone?: "info" | "success" | "warning" | "danger";
|
|
5
|
+
title?: string;
|
|
6
|
+
/** Body copy */
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
/** Right-aligned action slot */
|
|
9
|
+
action?: React.ReactNode;
|
|
10
|
+
style?: React.CSSProperties;
|
|
11
|
+
}
|
|
12
|
+
export declare function Alert(props: AlertProps): JSX.Element;
|
|
13
|
+
/** Centered empty state. Addition. */
|
|
14
|
+
export interface EmptyStateProps {
|
|
15
|
+
icon?: string;
|
|
16
|
+
title?: string;
|
|
17
|
+
hint?: string;
|
|
18
|
+
action?: React.ReactNode;
|
|
19
|
+
style?: React.CSSProperties;
|
|
20
|
+
}
|
|
21
|
+
export declare function EmptyState(props: EmptyStateProps): JSX.Element;
|
|
22
|
+
/** Pulsing loading block. Addition. */
|
|
23
|
+
export interface SkeletonProps {
|
|
24
|
+
width?: number | string;
|
|
25
|
+
height?: number | string;
|
|
26
|
+
radius?: string;
|
|
27
|
+
style?: React.CSSProperties;
|
|
28
|
+
}
|
|
29
|
+
export declare function Skeleton(props: SkeletonProps): JSX.Element;
|
|
30
|
+
/** Indeterminate spinner. Addition. */
|
|
31
|
+
export interface SpinnerProps {
|
|
32
|
+
size?: number;
|
|
33
|
+
color?: string;
|
|
34
|
+
style?: React.CSSProperties;
|
|
35
|
+
}
|
|
36
|
+
export declare function Spinner(props: SpinnerProps): JSX.Element;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Icon } from "../icons/Icon.jsx";
|
|
3
|
+
|
|
4
|
+
const alertTones = {
|
|
5
|
+
info: { bg: "var(--info-bg)", fg: "var(--info-fg)", icon: "info" },
|
|
6
|
+
success: { bg: "var(--success-bg)", fg: "var(--success-text)", icon: "circle-check" },
|
|
7
|
+
warning: { bg: "var(--warning-bg)", fg: "var(--warning-text)", icon: "triangle-alert" },
|
|
8
|
+
danger: { bg: "var(--danger-bg)", fg: "var(--danger-text)", icon: "triangle-alert" },
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/** Inline banner — tinted, no border, 13px title + 12px body. */
|
|
12
|
+
export function Alert({ tone = "info", title, children, action, style }) {
|
|
13
|
+
const t = alertTones[tone];
|
|
14
|
+
return (
|
|
15
|
+
<div style={{ display: "flex", gap: 10, alignItems: "flex-start", background: t.bg, borderRadius: "var(--radius-md)", padding: "10px 12px", ...style }}>
|
|
16
|
+
<span style={{ color: t.fg, display: "inline-flex", marginTop: 1 }}><Icon name={t.icon} size={15} /></span>
|
|
17
|
+
<div style={{ display: "flex", flexDirection: "column", gap: 2, flex: 1, minWidth: 0 }}>
|
|
18
|
+
{title ? <span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-base)", lineHeight: "var(--leading-base)", letterSpacing: "var(--tracking-base)", color: t.fg }}>{title}</span> : null}
|
|
19
|
+
{children ? <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-sm)", lineHeight: "var(--leading-sm)", color: "var(--text-body)" }}>{children}</span> : null}
|
|
20
|
+
</div>
|
|
21
|
+
{action}
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Empty state — 22px muted glyph, 13px/500 title, 12px hint, optional action. */
|
|
27
|
+
export function EmptyState({ icon = "file-text", title, hint, action, style }) {
|
|
28
|
+
return (
|
|
29
|
+
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 6, padding: "40px 24px", textAlign: "center", ...style }}>
|
|
30
|
+
<span style={{ color: "var(--text-muted)", marginBottom: 6 }}><Icon name={icon} size={22} strokeWidth={1.5} /></span>
|
|
31
|
+
<span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-base)", lineHeight: "var(--leading-base)", letterSpacing: "var(--tracking-base)", color: "var(--text-heading)" }}>{title}</span>
|
|
32
|
+
{hint ? <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-sm)", lineHeight: "var(--leading-sm)", color: "var(--text-secondary)", maxWidth: 320 }}>{hint}</span> : null}
|
|
33
|
+
{action ? <span style={{ paddingTop: 10 }}>{action}</span> : null}
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Loading placeholder block. */
|
|
39
|
+
export function Skeleton({ width = "100%", height = 12, radius = "var(--radius-sm)", style }) {
|
|
40
|
+
return <span style={{ display: "block", width, height, borderRadius: radius, background: "var(--skeleton)", animation: "kb-pulse 1.4s var(--ease-in-out) infinite", ...style }} />;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Indeterminate spinner (task-running affordance). */
|
|
44
|
+
export function Spinner({ size = 16, color = "var(--action-primary)", style }) {
|
|
45
|
+
return (
|
|
46
|
+
<span style={{ display: "inline-block", width: size, height: size, borderRadius: "var(--radius-full)", border: `2px solid var(--track)`, borderTopColor: color, animation: "kb-spin .7s linear infinite", ...style }} />
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import Icon from '../icons/Icon.vue'
|
|
4
|
+
const alertTones = {
|
|
5
|
+
info: { bg: 'var(--info-bg)', fg: 'var(--info-fg)', icon: 'info' },
|
|
6
|
+
success: { bg: 'var(--success-bg)', fg: 'var(--success-text)', icon: 'circle-check' },
|
|
7
|
+
warning: { bg: 'var(--warning-bg)', fg: 'var(--warning-text)', icon: 'triangle-alert' },
|
|
8
|
+
danger: { bg: 'var(--danger-bg)', fg: 'var(--danger-text)', icon: 'triangle-alert' },
|
|
9
|
+
}
|
|
10
|
+
// Alert — inline banner — tinted, no border, 13px title + 12px body.
|
|
11
|
+
const props = defineProps({ tone: { type: String, default: 'info' }, title: String, style: Object })
|
|
12
|
+
const t = computed(() => alertTones[props.tone])
|
|
13
|
+
</script>
|
|
14
|
+
<template>
|
|
15
|
+
<div :style="{ display: 'flex', gap: 10, alignItems: 'flex-start', background: t.bg, borderRadius: 'var(--radius-md)', padding: '10px 12px', ...style }">
|
|
16
|
+
<span :style="{ color: t.fg, display: 'inline-flex', marginTop: 1 }"><Icon :name="t.icon" :size="15" /></span>
|
|
17
|
+
<div style="display:flex;flex-direction:column;gap:2px;flex:1;min-width:0">
|
|
18
|
+
<span v-if="title" :style="{ fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-medium)', fontSize: 'var(--text-base)', lineHeight: 'var(--leading-base)', letterSpacing: 'var(--tracking-base)', color: t.fg }">{{ title }}</span>
|
|
19
|
+
<span style="font-family:var(--font-sans);font-size:var(--text-sm);line-height:var(--leading-sm);color:var(--text-body)"><slot /></span>
|
|
20
|
+
</div>
|
|
21
|
+
<slot name="action" />
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<!-- EmptyState — 22px muted glyph, 13px/500 title, 12px hint, optional action. -->
|
|
26
|
+
<!--
|
|
27
|
+
<script setup name="EmptyState">
|
|
28
|
+
import Icon from '../icons/Icon.vue'
|
|
29
|
+
defineProps({ icon: { type: String, default: 'file-text' }, title: String, hint: String, style: Object })
|
|
30
|
+
</script>
|
|
31
|
+
<template>
|
|
32
|
+
<div :style="{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 6, padding: '40px 24px', textAlign: 'center', ...style }">
|
|
33
|
+
<span style="color:var(--text-muted);margin-bottom:6px"><Icon :name="icon" :size="22" :stroke-width="1.5" /></span>
|
|
34
|
+
<span style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);color:var(--text-heading)">{{ title }}</span>
|
|
35
|
+
<span v-if="hint" style="font-family:var(--font-sans);font-size:var(--text-sm);line-height:var(--leading-sm);color:var(--text-secondary);max-width:320px">{{ hint }}</span>
|
|
36
|
+
<span v-if="$slots.action" style="padding-top:10px"><slot name="action" /></span>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
39
|
+
-->
|
|
40
|
+
|
|
41
|
+
<!-- Skeleton — loading placeholder block. -->
|
|
42
|
+
<!--
|
|
43
|
+
<script setup name="Skeleton">
|
|
44
|
+
defineProps({ width: { type: [String, Number], default: '100%' }, height: { type: [String, Number], default: 12 }, radius: { type: String, default: 'var(--radius-sm)' }, style: Object })
|
|
45
|
+
</script>
|
|
46
|
+
<template>
|
|
47
|
+
<span :style="{ display: 'block', width, height, borderRadius: radius, background: 'var(--skeleton)', animation: 'kb-pulse 1.4s var(--ease-in-out) infinite', ...style }" />
|
|
48
|
+
</template>
|
|
49
|
+
-->
|
|
50
|
+
|
|
51
|
+
<!-- Spinner — indeterminate spinner (task-running affordance). -->
|
|
52
|
+
<!--
|
|
53
|
+
<script setup name="Spinner">
|
|
54
|
+
defineProps({ size: { type: Number, default: 16 }, color: { type: String, default: 'var(--action-primary)' }, style: Object })
|
|
55
|
+
</script>
|
|
56
|
+
<template>
|
|
57
|
+
<span :style="{ display: 'inline-block', width: size, height: size, borderRadius: 'var(--radius-full)', border: '2px solid var(--track)', borderTopColor: color, animation: 'kb-spin .7s linear infinite', ...style }" />
|
|
58
|
+
</template>
|
|
59
|
+
-->
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
/** Page-level notification banner: tinted full-width strip, left accent bar, inline action link, dismiss ×. Use Alert for in-card messages, Toast for floating ones. */
|
|
4
|
+
export interface BannerProps {
|
|
5
|
+
tone?: "info" | "success" | "warning" | "danger";
|
|
6
|
+
/** Bold lead-in before the message */
|
|
7
|
+
title?: string;
|
|
8
|
+
/** Inline action link label */
|
|
9
|
+
action?: string;
|
|
10
|
+
onAction?: () => void;
|
|
11
|
+
dismissible?: boolean;
|
|
12
|
+
onDismiss?: () => void;
|
|
13
|
+
children?: React.ReactNode;
|
|
14
|
+
style?: React.CSSProperties;
|
|
15
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Icon } from "../icons/Icon.jsx";
|
|
3
|
+
import { IconButton } from "../buttons/IconButton.jsx";
|
|
4
|
+
|
|
5
|
+
const bannerTones = {
|
|
6
|
+
info: { bg: "var(--info-bg)", fg: "var(--info-fg)", icon: "info" },
|
|
7
|
+
success: { bg: "var(--success-bg)", fg: "var(--success-text)", icon: "circle-check" },
|
|
8
|
+
warning: { bg: "var(--warning-bg)", fg: "var(--warning-text)", icon: "triangle-alert" },
|
|
9
|
+
danger: { bg: "var(--danger-bg)", fg: "var(--danger-text)", icon: "triangle-alert" },
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/** Page-level notification banner (Carbon/SLDS scoped notification): full-width tinted strip with icon, message, optional inline action link and dismiss ×. Distinct from Alert (inline, in-card) and Toast (floating). */
|
|
13
|
+
export function Banner({ tone = "info", title, action, onAction, dismissible, onDismiss, children, style }) {
|
|
14
|
+
const t = bannerTones[tone];
|
|
15
|
+
return (
|
|
16
|
+
<div style={{ display: "flex", alignItems: "center", gap: 10, background: t.bg, borderLeft: `3px solid ${t.fg}`, padding: "10px 12px 10px 14px", boxSizing: "border-box", ...style }}>
|
|
17
|
+
<span style={{ color: t.fg, display: "inline-flex", flexShrink: 0 }}><Icon name={t.icon} size={16} /></span>
|
|
18
|
+
<span style={{ flex: 1, minWidth: 0, fontFamily: "var(--font-sans)", fontSize: "var(--text-sm)", lineHeight: "var(--leading-sm)", color: "var(--text-body)" }}>
|
|
19
|
+
{title && <strong style={{ fontWeight: "var(--weight-medium)", color: t.fg, paddingRight: 6 }}>{title}</strong>}{children}
|
|
20
|
+
</span>
|
|
21
|
+
{action && <button type="button" onClick={onAction} style={{ border: "none", background: "transparent", cursor: "pointer", padding: 0, fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-sm)", color: t.fg, textDecoration: "underline", whiteSpace: "nowrap", flexShrink: 0 }}>{action}</button>}
|
|
22
|
+
{dismissible && <IconButton icon="x" size="xs" muted label="Dismiss" onClick={onDismiss} />}
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import Icon from '../icons/Icon.vue'
|
|
4
|
+
import IconButton from '../buttons/IconButton.vue'
|
|
5
|
+
const bannerTones = {
|
|
6
|
+
info: { bg: 'var(--info-bg)', fg: 'var(--info-fg)', icon: 'info' },
|
|
7
|
+
success: { bg: 'var(--success-bg)', fg: 'var(--success-text)', icon: 'circle-check' },
|
|
8
|
+
warning: { bg: 'var(--warning-bg)', fg: 'var(--warning-text)', icon: 'triangle-alert' },
|
|
9
|
+
danger: { bg: 'var(--danger-bg)', fg: 'var(--danger-text)', icon: 'triangle-alert' },
|
|
10
|
+
}
|
|
11
|
+
// Page-level notification banner: tinted full-width strip, left accent bar, inline action link, dismiss ×.
|
|
12
|
+
const props = defineProps({ tone: { type: String, default: 'info' }, title: String, action: String, dismissible: Boolean, style: Object })
|
|
13
|
+
const emit = defineEmits(['action', 'dismiss'])
|
|
14
|
+
const t = computed(() => bannerTones[props.tone])
|
|
15
|
+
</script>
|
|
16
|
+
<template>
|
|
17
|
+
<div :style="{ display: 'flex', alignItems: 'center', gap: '10px', background: t.bg, borderLeft: `3px solid ${t.fg}`, padding: '10px 12px 10px 14px', boxSizing: 'border-box', ...style }">
|
|
18
|
+
<span :style="{ color: t.fg, display: 'inline-flex', flexShrink: 0 }"><Icon :name="t.icon" :size="16" /></span>
|
|
19
|
+
<span style="flex:1;min-width:0;font-family:var(--font-sans);font-size:var(--text-sm);line-height:var(--leading-sm);color:var(--text-body)">
|
|
20
|
+
<strong v-if="title" :style="{ fontWeight: 'var(--weight-medium)', color: t.fg, paddingRight: '6px' }">{{ title }}</strong><slot />
|
|
21
|
+
</span>
|
|
22
|
+
<button v-if="action" type="button" @click="emit('action')" :style="{ border: 'none', background: 'transparent', cursor: 'pointer', padding: 0, fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-medium)', fontSize: 'var(--text-sm)', color: t.fg, textDecoration: 'underline', whiteSpace: 'nowrap', flexShrink: 0 }">{{ action }}</button>
|
|
23
|
+
<IconButton v-if="dismissible" icon="x" size="xs" muted label="Dismiss" @click="emit('dismiss')" />
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/** Floating context menu — r10, soft shadow, 13px rows, red danger row. */
|
|
3
|
+
export interface ContextMenuProps {
|
|
4
|
+
items?: { label?: string; icon?: string; danger?: boolean; divider?: boolean }[];
|
|
5
|
+
onSelect?: (label: string) => void;
|
|
6
|
+
style?: React.CSSProperties;
|
|
7
|
+
}
|
|
8
|
+
export declare function ContextMenu(props: ContextMenuProps): JSX.Element;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Icon } from "../icons/Icon.jsx";
|
|
3
|
+
|
|
4
|
+
/** Right-click context menu (Preview / Duplicate / Delete). items: [{label, icon, danger, divider}]. */
|
|
5
|
+
export function ContextMenu({ items = [], onSelect, style }) {
|
|
6
|
+
const [hover, setHover] = React.useState(-1);
|
|
7
|
+
return (
|
|
8
|
+
<div style={{ background: "var(--bg-surface)", borderRadius: "var(--radius-lg)", border: "1px solid var(--border-card)", boxShadow: "var(--shadow-menu)", padding: 4, minWidth: 148, display: "inline-flex", flexDirection: "column", ...style }}>
|
|
9
|
+
{items.map((it, i) => it.divider ? <div key={i} style={{ height: 1, background: "var(--border-subtle)", margin: "4px 0" }} /> : (
|
|
10
|
+
<button key={i} type="button" onClick={() => onSelect && onSelect(it.label)}
|
|
11
|
+
onMouseEnter={() => setHover(i)} onMouseLeave={() => setHover(-1)}
|
|
12
|
+
style={{ display: "flex", alignItems: "center", gap: 10, padding: "7px 10px", borderRadius: "var(--radius-md)", border: "none", cursor: "pointer", background: hover === i ? "var(--bg-hover)" : "transparent", fontFamily: "var(--font-sans)", fontSize: "var(--text-base)", lineHeight: "var(--leading-base)", letterSpacing: "var(--tracking-base)", color: it.danger ? "var(--danger)" : "var(--text-heading)", textAlign: "left" }}>
|
|
13
|
+
{it.icon ? <Icon name={it.icon} size={15} /> : null}{it.label}
|
|
14
|
+
</button>
|
|
15
|
+
))}
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import Icon from '../icons/Icon.vue'
|
|
4
|
+
// Right-click context menu (Preview / Duplicate / Delete). items: [{label, icon, danger, divider}].
|
|
5
|
+
defineProps({ items: { type: Array, default: () => [] }, style: Object })
|
|
6
|
+
const emit = defineEmits(['select'])
|
|
7
|
+
const hover = ref(-1)
|
|
8
|
+
</script>
|
|
9
|
+
<template>
|
|
10
|
+
<div :style="{ background: 'var(--bg-surface)', borderRadius: 'var(--radius-lg)', border: '1px solid var(--border-card)', boxShadow: 'var(--shadow-menu)', padding: 4, minWidth: 148, display: 'inline-flex', flexDirection: 'column', ...style }">
|
|
11
|
+
<template v-for="(it, i) in items" :key="i">
|
|
12
|
+
<div v-if="it.divider" style="height:1px;background:var(--border-subtle);margin:4px 0" />
|
|
13
|
+
<button v-else type="button" @click="emit('select', it.label)" @mouseenter="hover = i" @mouseleave="hover = -1"
|
|
14
|
+
:style="{ display: 'flex', alignItems: 'center', gap: 10, padding: '7px 10px', borderRadius: 'var(--radius-md)', border: 'none', cursor: 'pointer', background: hover === i ? 'var(--bg-hover)' : 'transparent', fontFamily: 'var(--font-sans)', fontSize: 'var(--text-base)', lineHeight: 'var(--leading-base)', letterSpacing: 'var(--tracking-base)', color: it.danger ? 'var(--danger)' : 'var(--text-heading)', textAlign: 'left' }">
|
|
15
|
+
<Icon v-if="it.icon" :name="it.icon" :size="15" />{{ it.label }}
|
|
16
|
+
</button>
|
|
17
|
+
</template>
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
/** Right slide-out detail/settings panel over a scrim (Workday/SLDS panel pattern). Header, scrollable body, footer actions. */
|
|
4
|
+
export interface DrawerProps {
|
|
5
|
+
open?: boolean;
|
|
6
|
+
title?: string;
|
|
7
|
+
subtitle?: string;
|
|
8
|
+
/** Panel width (default 400, matches --panel-w) */
|
|
9
|
+
width?: number;
|
|
10
|
+
/** Render in-flow (no fixed overlay) for demos/cards */
|
|
11
|
+
inline?: boolean;
|
|
12
|
+
/** Inline height (default 420) */
|
|
13
|
+
height?: number | string;
|
|
14
|
+
footer?: React.ReactNode;
|
|
15
|
+
onClose?: () => void;
|
|
16
|
+
children?: React.ReactNode;
|
|
17
|
+
style?: React.CSSProperties;
|
|
18
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { IconButton } from "../buttons/IconButton.jsx";
|
|
3
|
+
|
|
4
|
+
/** Right slide-out panel over a scrim: 17.5px title + subtitle, scrollable body, right-aligned footer slot. inline=true renders it in-flow for embedding in cards/demos. */
|
|
5
|
+
export function Drawer({ open = true, title, subtitle, width = 400, inline, height, footer, onClose, children, style }) {
|
|
6
|
+
if (!open) return null;
|
|
7
|
+
const panel = (
|
|
8
|
+
<div style={{ width, maxWidth: "100%", height: inline ? (height || 420) : "100%", background: "var(--bg-raised)", borderLeft: "1px solid var(--border-card)", boxShadow: inline ? "var(--shadow-menu)" : "-8px 0 24px rgba(0,0,0,.12)", display: "flex", flexDirection: "column", boxSizing: "border-box", ...(inline ? { border: "1px solid var(--border-card)", borderRadius: "var(--radius-lg)" } : null), ...style }}>
|
|
9
|
+
<div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", padding: "16px 16px 12px", borderBottom: "1px solid var(--border-card)", flexShrink: 0 }}>
|
|
10
|
+
<div style={{ display: "flex", flexDirection: "column", gap: 3 }}>
|
|
11
|
+
<span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-semibold)", fontSize: "var(--text-md)", lineHeight: "var(--leading-md)", letterSpacing: "var(--tracking-md)", color: "var(--text-heading)" }}>{title}</span>
|
|
12
|
+
{subtitle && <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-sm)", lineHeight: "var(--leading-sm)", color: "var(--text-secondary)" }}>{subtitle}</span>}
|
|
13
|
+
</div>
|
|
14
|
+
<IconButton icon="x" size="md" label="Close" onClick={onClose} />
|
|
15
|
+
</div>
|
|
16
|
+
<div style={{ flex: 1, overflowY: "auto", padding: 16 }}>{children}</div>
|
|
17
|
+
{footer && <div style={{ display: "flex", justifyContent: "flex-end", gap: 8, padding: "12px 16px", borderTop: "1px solid var(--border-card)", flexShrink: 0 }}>{footer}</div>}
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
if (inline) return panel;
|
|
21
|
+
return (
|
|
22
|
+
<div onClick={onClose} style={{ position: "fixed", inset: 0, zIndex: "var(--z-modal)", background: "var(--bg-scrim)", display: "flex", justifyContent: "flex-end", animation: "kb-fade-in var(--dur-fast) var(--ease-out)" }}>
|
|
23
|
+
<div onClick={(e) => e.stopPropagation()} style={{ height: "100%", animation: "kb-slide-in var(--dur) var(--ease-out)" }}>{panel}</div>
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import IconButton from '../buttons/IconButton.vue'
|
|
3
|
+
// Right slide-out panel over a scrim; inline=true renders in-flow for demos. Header, scrollable body, footer slot.
|
|
4
|
+
defineProps({ open: { type: Boolean, default: true }, title: String, subtitle: String, width: { type: Number, default: 400 }, inline: Boolean, height: { type: [Number, String], default: 420 }, style: Object })
|
|
5
|
+
const emit = defineEmits(['close'])
|
|
6
|
+
</script>
|
|
7
|
+
<template>
|
|
8
|
+
<component :is="inline ? 'div' : 'teleport'" v-if="open" v-bind="inline ? {} : { to: 'body' }">
|
|
9
|
+
<div v-if="!inline" @click="emit('close')" style="position:fixed;inset:0;z-index:var(--z-modal);background:var(--bg-scrim);display:flex;justify-content:flex-end;animation:kb-fade-in var(--dur-fast) var(--ease-out)">
|
|
10
|
+
<div @click.stop style="height:100%;animation:kb-slide-in var(--dur) var(--ease-out)"><DrawerPanel /></div>
|
|
11
|
+
</div>
|
|
12
|
+
<div :style="{ width: width + 'px', height: inline ? (typeof height === 'number' ? height + 'px' : height) : '100%', background: 'var(--bg-raised)', border: '1px solid var(--border-card)', borderRadius: inline ? 'var(--radius-lg)' : 0, boxShadow: 'var(--shadow-menu)', display: 'flex', flexDirection: 'column', boxSizing: 'border-box', ...style }">
|
|
13
|
+
<div style="display:flex;align-items:flex-start;justify-content:space-between;padding:16px 16px 12px;border-bottom:1px solid var(--border-card);flex-shrink:0">
|
|
14
|
+
<div style="display:flex;flex-direction:column;gap:3px">
|
|
15
|
+
<span style="font-family:var(--font-sans);font-weight:var(--weight-semibold);font-size:var(--text-md);color:var(--text-heading)">{{ title }}</span>
|
|
16
|
+
<span v-if="subtitle" style="font-family:var(--font-sans);font-size:var(--text-sm);color:var(--text-secondary)">{{ subtitle }}</span>
|
|
17
|
+
</div>
|
|
18
|
+
<IconButton icon="x" size="md" label="Close" @click="emit('close')" />
|
|
19
|
+
</div>
|
|
20
|
+
<div style="flex:1;overflow-y:auto;padding:16px"><slot /></div>
|
|
21
|
+
<div v-if="$slots.footer" style="display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--border-card);flex-shrink:0"><slot name="footer" /></div>
|
|
22
|
+
</div>
|
|
23
|
+
</component>
|
|
24
|
+
</template>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/** Trigger-anchored dropdown menu (reuses ContextMenu's look). Addition — for "Show ⌄"-style buttons and user menus. */
|
|
3
|
+
export interface MenuProps {
|
|
4
|
+
trigger: React.ReactNode;
|
|
5
|
+
items?: { label?: string; icon?: string; danger?: boolean; divider?: boolean }[];
|
|
6
|
+
onSelect?: (label: string) => void;
|
|
7
|
+
align?: "start" | "end";
|
|
8
|
+
style?: React.CSSProperties;
|
|
9
|
+
}
|
|
10
|
+
export declare function Menu(props: MenuProps): JSX.Element;
|