@keyfunc/keybricks-ds 1.0.3 → 2.1.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/DEPLOY.md +4 -4
- package/DESIGN.md +154 -53
- package/INTEGRATION.md +176 -36
- package/SKILL.md +6 -4
- package/_adherence.oxlintrc.json +183 -72
- package/_scripts/build-index.mjs +9 -0
- package/_scripts/build-tokens.mjs +5 -2
- package/assets/icons/icon-index.js +1 -1
- package/assets/icons/icon-index.json +1 -1
- package/components/_cards/accordion.card.html +2 -2
- package/components/_cards/action-chip.card.html +8 -3
- package/components/_cards/activity.card.html +2 -2
- package/components/_cards/alert.card.html +2 -2
- package/components/_cards/app-chrome.card.html +4 -4
- package/components/_cards/banner.card.html +1 -1
- package/components/_cards/breadcrumb.card.html +2 -2
- package/components/_cards/button-1-base.card.html +2 -2
- package/components/_cards/button-2-states.card.html +14 -14
- package/components/_cards/button-3-sizes-icons.card.html +1 -1
- package/components/_cards/button-4-group.card.html +5 -5
- package/components/_cards/canvas-zoom-controls.card.html +1 -1
- package/components/_cards/cards-indicators.card.html +2 -2
- package/components/_cards/charts-1-sparkline.card.html +2 -2
- package/components/_cards/charts-10-gauge.card.html +4 -4
- package/components/_cards/charts-11-funnel.card.html +2 -2
- package/components/_cards/charts-12-treemap.card.html +2 -2
- package/components/_cards/charts-14-radar.card.html +1 -1
- package/components/_cards/charts-15-distribution.card.html +1 -1
- package/components/_cards/charts-16-pareto.card.html +2 -2
- package/components/_cards/charts-17-candlestick.card.html +2 -2
- package/components/_cards/charts-18-sankey.card.html +2 -2
- package/components/_cards/charts-19-chord.card.html +2 -2
- package/components/_cards/charts-2-line.card.html +2 -2
- package/components/_cards/charts-20-sunburst.card.html +2 -2
- package/components/_cards/charts-21-worldmap.card.html +2 -2
- package/components/_cards/charts-22-gantt.card.html +2 -2
- package/components/_cards/charts-23-bar3d.card.html +2 -2
- package/components/_cards/charts-24-pie3d.card.html +2 -2
- package/components/_cards/charts-25-surface3d.card.html +2 -2
- package/components/_cards/charts-26-scatter3d.card.html +2 -2
- package/components/_cards/charts-27-ribbon3d.card.html +2 -2
- package/components/_cards/charts-3-bar.card.html +2 -2
- package/components/_cards/charts-4-barlist.card.html +2 -2
- package/components/_cards/charts-5-donut.card.html +3 -3
- package/components/_cards/charts-6-scatter.card.html +2 -2
- package/components/_cards/charts-7-heatmap.card.html +2 -2
- package/components/_cards/charts-8-waterfall.card.html +2 -2
- package/components/_cards/charts-9-bullet.card.html +2 -2
- package/components/_cards/charts-99-fullpage.card.html +5 -5
- package/components/_cards/checkbox.card.html +4 -4
- package/components/_cards/codeblock.card.html +1 -1
- package/components/_cards/combobox.card.html +3 -2
- package/components/_cards/context-menu.card.html +3 -2
- package/components/_cards/date-picker.card.html +5 -2
- package/components/_cards/diffvalue.card.html +2 -2
- package/components/_cards/divider.card.html +3 -3
- package/components/_cards/drawer.card.html +2 -2
- package/components/_cards/dropdown-menu.card.html +6 -6
- package/components/_cards/dropzone.card.html +1 -1
- package/components/_cards/empty-state.card.html +5 -5
- package/components/_cards/filter-bar.card.html +5 -5
- package/components/_cards/icon-button.card.html +2 -2
- package/components/_cards/icons-1-core.card.html +2 -2
- package/components/_cards/icons-2-feather.card.html +3 -3
- package/components/_cards/icons-3-unicons.card.html +3 -3
- package/components/_cards/input.card.html +5 -2
- package/components/_cards/kbd.card.html +2 -2
- package/components/_cards/keyvalue.card.html +2 -2
- package/components/_cards/listrow.card.html +2 -2
- package/components/_cards/loading.card.html +2 -2
- package/components/_cards/log-viewer.card.html +2 -2
- package/components/_cards/modal.card.html +9 -9
- package/components/_cards/multi-select.card.html +3 -2
- package/components/_cards/number-stepper.card.html +3 -2
- package/components/_cards/pagination.card.html +3 -2
- package/components/_cards/people.card.html +3 -3
- package/components/_cards/pipeline-node.card.html +2 -2
- package/components/_cards/pipeline-palette.card.html +4 -4
- package/components/_cards/radio.card.html +46 -0
- package/components/_cards/search.card.html +5 -2
- package/components/_cards/segmented-control.card.html +39 -0
- package/components/_cards/select.card.html +4 -4
- package/components/_cards/slider.card.html +1 -1
- package/components/_cards/smart-table.card.html +1 -1
- package/components/_cards/spreadsheet.card.html +2 -2
- package/components/_cards/stepper.card.html +2 -2
- package/components/_cards/table.card.html +103 -0
- package/components/_cards/tabs.card.html +3 -2
- package/components/_cards/tag.card.html +5 -2
- package/components/_cards/textarea.card.html +2 -2
- package/components/_cards/timeline.card.html +1 -1
- package/components/_cards/toast.card.html +4 -4
- package/components/_cards/toggles.card.html +45 -56
- package/components/_cards/tooltip.card.html +5 -5
- package/components/_cards/tree.card.html +2 -2
- package/components/_shared/src-buttons.js +1 -1
- package/components/_shared/src-charts.js +1 -1
- package/components/_shared/src-data.js +1 -1
- package/components/_shared/src-display.js +1 -1
- package/components/_shared/src-feedback.js +1 -1
- package/components/_shared/src-forms.js +1 -1
- package/components/_shared/src-navigation.js +1 -1
- package/components/_shared/src-pipeline.js +1 -1
- package/components/_shared/src-tabs.js +1 -1
- package/components/_shared/view-source.js +9 -4
- package/components/_vue/index.mjs +9 -5
- package/components/buttons/ActionChip.d.ts +3 -1
- package/components/buttons/ActionChip.jsx +4 -4
- package/components/buttons/ActionChip.vue +4 -4
- package/components/buttons/Button.d.ts +5 -2
- package/components/buttons/Button.jsx +15 -18
- package/components/buttons/Button.vue +17 -18
- package/components/buttons/ButtonGroup.vue +1 -1
- package/components/buttons/IconButton.d.ts +2 -1
- package/components/buttons/IconButton.jsx +9 -7
- package/components/buttons/IconButton.vue +10 -8
- package/components/buttons/buttons.prompt.md +6 -5
- package/components/charts/Bar3D.jsx +2 -2
- package/components/charts/Bar3D.vue +2 -2
- package/components/charts/BarChart.jsx +4 -4
- package/components/charts/BarChart.vue +4 -4
- package/components/charts/BarList.jsx +1 -1
- package/components/charts/BarList.vue +1 -1
- package/components/charts/BoxPlot.jsx +1 -1
- package/components/charts/BoxPlot.vue +2 -2
- package/components/charts/BulletChart.jsx +1 -1
- package/components/charts/BulletChart.vue +1 -1
- package/components/charts/CandlestickChart.jsx +2 -2
- package/components/charts/CandlestickChart.vue +3 -3
- package/components/charts/ChartKit.jsx +5 -5
- package/components/charts/ChartLegend.vue +16 -0
- package/components/charts/ChartTooltip.vue +16 -0
- package/components/charts/ChordChart.jsx +2 -2
- package/components/charts/ChordChart.vue +2 -2
- package/components/charts/GanttChart.jsx +2 -2
- package/components/charts/GanttChart.vue +2 -2
- package/components/charts/GaugeChart.jsx +2 -2
- package/components/charts/GaugeChart.vue +2 -2
- package/components/charts/HeatmapChart.jsx +2 -2
- package/components/charts/HeatmapChart.vue +2 -2
- package/components/charts/Histogram.jsx +2 -2
- package/components/charts/Histogram.vue +3 -3
- package/components/charts/LineChart.jsx +1 -1
- package/components/charts/LineChart.vue +3 -3
- package/components/charts/ParetoChart.jsx +3 -3
- package/components/charts/ParetoChart.vue +4 -4
- package/components/charts/PlotGrid.vue +18 -0
- package/components/charts/RadarChart.jsx +1 -1
- package/components/charts/RadarChart.vue +1 -1
- package/components/charts/Ribbon3D.jsx +2 -2
- package/components/charts/Ribbon3D.vue +2 -2
- package/components/charts/SankeyChart.jsx +2 -2
- package/components/charts/SankeyChart.vue +2 -2
- package/components/charts/Scatter3D.jsx +1 -1
- package/components/charts/Scatter3D.vue +1 -1
- package/components/charts/ScatterChart.jsx +3 -3
- package/components/charts/ScatterChart.vue +4 -4
- package/components/charts/Sparkline.jsx +1 -1
- package/components/charts/Sparkline.vue +1 -1
- package/components/charts/SunburstChart.jsx +1 -1
- package/components/charts/SunburstChart.vue +1 -1
- package/components/charts/Surface3D.jsx +2 -2
- package/components/charts/Surface3D.vue +2 -2
- package/components/charts/TreemapChart.jsx +2 -2
- package/components/charts/TreemapChart.vue +2 -2
- package/components/charts/WaterfallChart.jsx +2 -2
- package/components/charts/WaterfallChart.vue +3 -3
- package/components/charts/WorldMap.jsx +2 -2
- package/components/charts/WorldMap.vue +2 -2
- package/components/charts/XLabels.vue +11 -0
- package/components/data/CodeBlock.jsx +1 -1
- package/components/data/CodeBlock.vue +1 -1
- package/components/data/DiffValue.jsx +1 -1
- package/components/data/DiffValue.vue +1 -1
- package/components/data/FilterBar.d.ts +2 -0
- package/components/data/FilterBar.jsx +10 -9
- package/components/data/FilterBar.vue +9 -8
- package/components/data/KeyValue.jsx +3 -3
- package/components/data/KeyValue.vue +3 -3
- package/components/data/ListRow.jsx +2 -2
- package/components/data/ListRow.vue +2 -2
- package/components/data/Pagination.d.ts +5 -1
- package/components/data/Pagination.jsx +16 -12
- package/components/data/Pagination.vue +14 -9
- package/components/data/SmartTable.d.ts +4 -1
- package/components/data/SmartTable.jsx +16 -14
- package/components/data/SmartTable.vue +25 -22
- package/components/data/Spreadsheet.d.ts +2 -0
- package/components/data/Spreadsheet.jsx +12 -11
- package/components/data/Spreadsheet.vue +14 -13
- package/components/data/Table.d.ts +47 -0
- package/components/data/Table.jsx +85 -0
- package/components/data/Table.vue +63 -0
- package/components/data/data.prompt.md +3 -3
- package/components/display/Avatar.vue +3 -2
- package/components/display/AvatarGroup.vue +3 -2
- package/components/display/Badge.vue +1 -1
- package/components/display/Divider.vue +3 -3
- package/components/display/Donut.vue +3 -2
- package/components/display/IconTile.vue +2 -1
- package/components/display/Kbd.vue +1 -1
- package/components/display/ProgressBar.jsx +1 -1
- package/components/display/ProgressBar.vue +1 -1
- package/components/display/StatCard.vue +1 -1
- package/components/display/Tag.d.ts +3 -1
- package/components/display/Tag.jsx +4 -4
- package/components/display/Tag.vue +4 -4
- package/components/feedback/Accordion.jsx +2 -2
- package/components/feedback/Accordion.vue +2 -2
- package/components/feedback/ActivityItem.d.ts +3 -1
- package/components/feedback/ActivityItem.jsx +5 -5
- package/components/feedback/ActivityItem.vue +5 -4
- package/components/feedback/Alert.jsx +4 -4
- package/components/feedback/Alert.vue +3 -3
- package/components/feedback/Banner.jsx +5 -5
- package/components/feedback/Banner.vue +5 -5
- package/components/feedback/ContextMenu.d.ts +3 -1
- package/components/feedback/ContextMenu.jsx +5 -5
- package/components/feedback/ContextMenu.vue +5 -5
- package/components/feedback/DotActivity.vue +3 -3
- package/components/feedback/Drawer.d.ts +2 -0
- package/components/feedback/Drawer.jsx +6 -6
- package/components/feedback/Drawer.vue +22 -15
- package/components/feedback/EmptyState.vue +2 -2
- package/components/feedback/LogViewer.vue +1 -1
- package/components/feedback/Modal.d.ts +2 -0
- package/components/feedback/Modal.jsx +12 -11
- package/components/feedback/Modal.vue +10 -8
- package/components/feedback/Skeleton.vue +2 -1
- package/components/feedback/Spinner.vue +2 -1
- package/components/feedback/Stepper.vue +1 -1
- package/components/feedback/Timeline.jsx +1 -1
- package/components/feedback/Timeline.vue +1 -1
- package/components/feedback/Toast.vue +4 -4
- package/components/feedback/ToastStack.vue +11 -0
- package/components/feedback/Tooltip.vue +19 -0
- package/components/feedback/feedback.prompt.md +4 -4
- package/components/forms/Checkbox.d.ts +3 -2
- package/components/forms/Checkbox.jsx +7 -7
- package/components/forms/Checkbox.vue +8 -8
- package/components/forms/Combobox.d.ts +2 -0
- package/components/forms/Combobox.jsx +12 -10
- package/components/forms/Combobox.vue +11 -10
- package/components/forms/DatePicker.d.ts +4 -0
- package/components/forms/DatePicker.jsx +16 -12
- package/components/forms/DatePicker.vue +15 -11
- package/components/forms/Dropzone.jsx +2 -2
- package/components/forms/Dropzone.vue +5 -5
- package/components/forms/Field.d.ts +5 -1
- package/components/forms/Field.jsx +4 -4
- package/components/forms/Field.vue +4 -4
- package/components/forms/Input.d.ts +5 -1
- package/components/forms/Input.jsx +7 -7
- package/components/forms/Input.vue +3 -3
- package/components/forms/MultiSelect.d.ts +2 -0
- package/components/forms/MultiSelect.jsx +13 -11
- package/components/forms/MultiSelect.vue +12 -11
- package/components/forms/NumberStepper.d.ts +3 -1
- package/components/forms/NumberStepper.jsx +7 -7
- package/components/forms/NumberStepper.vue +8 -7
- package/components/forms/Radio.d.ts +30 -0
- package/components/forms/Radio.jsx +65 -0
- package/components/forms/Radio.vue +17 -9
- package/components/forms/RadioGroup.vue +22 -4
- package/components/forms/SearchInput.d.ts +3 -1
- package/components/forms/SearchInput.jsx +6 -6
- package/components/forms/SearchInput.vue +7 -6
- package/components/forms/Select.d.ts +3 -2
- package/components/forms/Select.jsx +6 -7
- package/components/forms/Select.vue +6 -6
- package/components/forms/Slider.jsx +3 -3
- package/components/forms/Slider.vue +3 -3
- package/components/forms/Switch.d.ts +32 -24
- package/components/forms/Switch.jsx +85 -35
- package/components/forms/Switch.vue +57 -11
- package/components/forms/Textarea.vue +4 -4
- package/components/forms/forms.prompt.md +4 -1
- package/components/forms/input-base.js +2 -1
- package/components/index.d.ts +2 -2
- package/components/index.js +5 -5
- package/components/navigation/Breadcrumb.jsx +3 -3
- package/components/navigation/Breadcrumb.vue +4 -4
- package/components/navigation/DocTree.jsx +3 -3
- package/components/navigation/DocTree.vue +3 -3
- package/components/navigation/PageHeading.vue +1 -1
- package/components/navigation/PageToolbar.vue +7 -6
- package/components/navigation/Sidebar.jsx +1 -1
- package/components/navigation/Sidebar.vue +3 -3
- package/components/navigation/ThemeToggle.vue +2 -1
- package/components/navigation/TopBar.d.ts +3 -1
- package/components/navigation/TopBar.jsx +6 -6
- package/components/navigation/Tree.jsx +5 -5
- package/components/navigation/Tree.vue +5 -5
- package/components/pipeline/ConfigPanel.d.ts +2 -0
- package/components/pipeline/ConfigPanel.jsx +9 -9
- package/components/pipeline/ConfigPanel.vue +9 -9
- package/components/pipeline/DataPreview.d.ts +3 -1
- package/components/pipeline/DataPreview.jsx +7 -7
- package/components/pipeline/DataPreview.vue +7 -7
- package/components/pipeline/NodeCard.jsx +3 -3
- package/components/pipeline/NodeCard.vue +3 -3
- package/components/pipeline/PaletteItem.vue +2 -2
- package/components/pipeline/PaletteListItem.vue +1 -1
- package/components/pipeline/PalettePanel.jsx +2 -2
- package/components/pipeline/PalettePanel.vue +1 -1
- package/components/pipeline/Port.vue +15 -0
- package/components/pipeline/PortLabel.vue +15 -0
- package/components/pipeline/ZoomControls.vue +1 -1
- package/components/pipeline/port-skin.js +13 -0
- package/components/px.js +4 -0
- package/components/tabs/PanelTabs.vue +5 -4
- package/components/tabs/PillTabs.vue +5 -4
- package/components/tabs/SegmentedControl.d.ts +11 -4
- package/components/tabs/SegmentedControl.jsx +25 -10
- package/components/tabs/SegmentedControl.vue +19 -7
- package/components/tabs/Tabs.d.ts +5 -3
- package/components/tabs/Tabs.jsx +15 -15
- package/components/tabs/Tabs.vue +5 -5
- package/components/tabs/ViewToggle.d.ts +3 -1
- package/components/tabs/ViewToggle.jsx +5 -5
- package/components/tabs/ViewToggle.vue +5 -5
- package/components/tabs/tabs.prompt.md +4 -2
- package/keybricks.css +4 -0
- package/package.json +6 -3
- package/readme.md +90 -123
- package/readme.zh-CN.md +120 -0
- package/tokens/charts.css +20 -17
- package/tokens/colors.css +2 -2
- package/tokens/dark.css +2 -2
- package/tokens/hover.css +32 -0
- package/tokens/interaction.css +3 -1
- package/tokens/layout.css +29 -7
- package/tokens/tokens.d.ts +36 -0
- package/tokens/tokens.js +143 -89
- package/tokens/tokens.json +240 -106
- package/tokens/typography.css +27 -14
- package/components/_cards/brand-visual.card.html +0 -43
- package/components/_cards/datatable.card.html +0 -48
- package/components/_shared/src-brand.js +0 -1
- package/components/brand/BrandVisual.d.ts +0 -17
- package/components/brand/BrandVisual.jsx +0 -29
- package/components/brand/BrandVisual.vue +0 -34
- package/components/brand/_dir.card.html +0 -13
- package/components/brand/brandMotifs.js +0 -210
- package/components/buttons/_dir.card.html +0 -13
- package/components/charts/ChartKit.vue +0 -47
- package/components/charts/_dir.card.html +0 -7
- package/components/data/DataTable.d.ts +0 -28
- package/components/data/DataTable.jsx +0 -32
- package/components/data/DataTable.vue +0 -25
- package/components/data/_dir.card.html +0 -13
- package/components/display/_dir.card.html +0 -13
- package/components/feedback/_dir.card.html +0 -13
- package/components/forms/_dir.card.html +0 -13
- package/components/icons/_dir.card.html +0 -13
- package/components/navigation/_dir.card.html +0 -13
- package/components/pipeline/_dir.card.html +0 -13
- package/components/tabs/_dir.card.html +0 -13
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import Icon from '../icons/Icon.vue'
|
|
4
|
+
import { portSkin } from './port-skin.js'
|
|
5
|
+
// Labeled input port pill ("A >", "B >") — 28×22, same three tones as Port.
|
|
6
|
+
defineProps({ label: { type: String, default: 'A' }, tone: { type: String, default: 'default' }, interactive: Boolean, style: Object })
|
|
7
|
+
const hover = ref(false)
|
|
8
|
+
</script>
|
|
9
|
+
<template>
|
|
10
|
+
<span @mouseenter="hover = true" @mouseleave="hover = false"
|
|
11
|
+
:style="{ width: '28px', height: '22px', borderRadius: 'var(--radius-full)', boxSizing: 'border-box', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: '2px', fontFamily: 'var(--font-sans)', fontSize: 'var(--text-xs)', letterSpacing: 'var(--tracking-xs)', lineHeight: 1, ...portSkin(tone, hover, interactive), ...style }">
|
|
12
|
+
<Icon v-if="tone === 'target'" name="plus" :size="12" :stroke-width="2.2" />
|
|
13
|
+
<template v-else>{{ label }}<Icon name="chevron-right" :size="9" :stroke-width="2.5" /></template>
|
|
14
|
+
</span>
|
|
15
|
+
</template>
|
|
@@ -5,7 +5,7 @@ const props = defineProps({ modelValue: { type: Number, default: 100 }, style: O
|
|
|
5
5
|
const emit = defineEmits(['update:modelValue', 'fit'])
|
|
6
6
|
</script>
|
|
7
7
|
<template>
|
|
8
|
-
<div :style="{ display: 'inline-flex', alignItems: 'center', gap:
|
|
8
|
+
<div :style="{ display: 'inline-flex', alignItems: 'center', gap: '2px', background: 'var(--bg-surface)', border: '1px solid var(--border-control)', borderRadius: 'var(--radius-md)', boxShadow: 'var(--shadow-menu)', padding: '3px', boxSizing: 'border-box', ...style }">
|
|
9
9
|
<IconButton icon="minus" size="sm" label="Zoom out" @click="emit('update:modelValue', Math.max(25, modelValue - 10))" />
|
|
10
10
|
<span style="min-width:40px;text-align:center;font-family:var(--font-sans);font-size:var(--text-xs);color:var(--text-secondary)">{{ modelValue }}%</span>
|
|
11
11
|
<IconButton icon="plus" size="sm" label="Zoom in" @click="emit('update:modelValue', Math.min(200, modelValue + 10))" />
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Shared port skin for Port.vue / PortLabel.vue / NodeCard.vue — mirrors portSkin() in NodeCard.jsx.
|
|
2
|
+
// tone: "default" | "active" (a wire is being dragged from it) | "target" (valid drop here).
|
|
3
|
+
export function portSkin(tone, hover, interactive) {
|
|
4
|
+
const hot = tone === 'active' || tone === 'target' || (interactive && hover)
|
|
5
|
+
return {
|
|
6
|
+
background: tone === 'target' ? 'var(--soft-bg)' : 'var(--bg-surface)',
|
|
7
|
+
border: `2px solid ${hot ? 'var(--action-primary)' : 'var(--port-border)'}`,
|
|
8
|
+
boxShadow: tone === 'active' || tone === 'target' ? '0 0 0 3px var(--focus-ring)' : 'none',
|
|
9
|
+
color: hot ? 'var(--action-primary)' : 'var(--text-muted)',
|
|
10
|
+
cursor: interactive ? (tone === 'active' ? 'grabbing' : 'grab') : 'default',
|
|
11
|
+
transition: 'var(--t-hover)'
|
|
12
|
+
}
|
|
13
|
+
}
|
package/components/px.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Vue's :style binding does not append "px" to numbers the way React does —
|
|
2
|
+
// { height: 30 } is silently dropped by the browser. Wrap any numeric length in px().
|
|
3
|
+
// Strings ('100%', 'var(--radius-md)', '12px') pass through untouched.
|
|
4
|
+
export const px = (v) => (typeof v === 'number' ? v + 'px' : v)
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
|
|
2
|
+
// Panel tabs (Node Info · Calc Rules · …): a lighter underline tab bar at the region's bar height with regular-weight control text. Put the panel in an sm region for the compact 32px/12px look.
|
|
3
|
+
defineProps({ tabs: { type: Array, default: () => [] }, active: String, size: String, style: Object })
|
|
3
4
|
const emit = defineEmits(['change'])
|
|
4
5
|
</script>
|
|
5
6
|
<template>
|
|
6
|
-
<div :style="{ display: 'flex', borderBottom: '1px solid var(--border-subtle)', ...style }">
|
|
7
|
-
<button v-for="t in tabs" :key="t" type="button" @click="emit('change', t)"
|
|
8
|
-
:style="{ background: 'transparent', border: 'none', cursor: 'pointer', padding: '
|
|
7
|
+
<div role="tablist" :data-size="size" :style="{ display: 'flex', borderBottom: '1px solid var(--border-subtle)', ...style }">
|
|
8
|
+
<button v-for="t in tabs" :key="t" type="button" role="tab" :aria-selected="t === active" :data-ink="t === active ? undefined : ''" @click="emit('change', t)"
|
|
9
|
+
:style="{ background: 'transparent', border: 'none', cursor: 'pointer', height: 'var(--bar-h)', boxSizing: 'border-box', padding: '0 var(--control-px)', marginBottom: '-1px', borderBottom: t === active ? '2px solid var(--action-primary)' : '2px solid transparent', fontFamily: 'var(--font-sans)', fontSize: 'var(--control-text)', lineHeight: 'var(--control-leading)', letterSpacing: 'var(--control-tracking)', color: t === active ? 'var(--action-primary)' : 'var(--ink, var(--text-secondary))', whiteSpace: 'nowrap' }">{{ t }}</button>
|
|
9
10
|
</div>
|
|
10
11
|
</template>
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
|
|
2
|
+
// Text pill filter tabs. Active = tinted pill. Pills are control-height (sm 24 · md 32 · lg 36); omit `size` to inherit.
|
|
3
|
+
defineProps({ tabs: { type: Array, default: () => [] }, active: String, size: String, style: Object })
|
|
3
4
|
const emit = defineEmits(['change'])
|
|
4
5
|
</script>
|
|
5
6
|
<template>
|
|
6
|
-
<div :style="{ display: 'flex', gap:
|
|
7
|
-
<button v-for="t in tabs" :key="t" type="button" @click="emit('change', t)"
|
|
8
|
-
:style="{ background: t === active ? 'var(--bg-active)' : 'transparent', border: 'none', cursor: 'pointer', height:
|
|
7
|
+
<div role="tablist" :data-size="size" :style="{ display: 'flex', gap: 'var(--control-gap)', ...style }">
|
|
8
|
+
<button v-for="t in tabs" :key="t" type="button" role="tab" :aria-selected="t === active" :data-ink="t === active ? undefined : ''" :data-wash="t === active ? undefined : ''" @click="emit('change', t)"
|
|
9
|
+
:style="{ background: t === active ? 'var(--bg-active)' : 'var(--wash, transparent)', border: 'none', cursor: 'pointer', height: 'var(--control-h)', padding: '0 var(--control-px)', borderRadius: 'var(--radius-md)', fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-medium)', fontSize: 'var(--control-text)', lineHeight: 'var(--control-leading)', letterSpacing: 'var(--control-tracking)', color: t === active ? 'var(--text-heading)' : 'var(--ink, var(--text-secondary))', whiteSpace: 'nowrap' }">{{ t }}</button>
|
|
9
10
|
</div>
|
|
10
11
|
</template>
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
/** Inset segmented control with a raised active segment
|
|
2
|
+
/** Inset segmented control with a raised active segment — switches views of the same data, applies instantly. ← → move between enabled segments. */
|
|
3
3
|
export interface SegmentedControlProps {
|
|
4
|
-
/** Plain labels, or {label, icon} entries */
|
|
5
|
-
options?: (string | { label: string; icon?: string })[];
|
|
4
|
+
/** Plain labels, or { label, icon?, disabled? } entries. Value is matched by label. */
|
|
5
|
+
options?: (string | { label: string; icon?: string; disabled?: boolean })[];
|
|
6
6
|
value?: string;
|
|
7
7
|
onChange?: (value: string) => void;
|
|
8
|
-
|
|
8
|
+
/** Size tier: sm 24 · md 32 · lg 36. Omit to inherit the enclosing region's tier (the default). */
|
|
9
|
+
size?: "sm" | "md" | "lg";
|
|
10
|
+
/** Hide labels; each label becomes the segment's aria-label and tooltip */
|
|
11
|
+
iconOnly?: boolean;
|
|
12
|
+
/** Greys the whole control */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Stretch to the container, segments share the width evenly */
|
|
15
|
+
fullWidth?: boolean;
|
|
9
16
|
style?: React.CSSProperties;
|
|
10
17
|
}
|
|
11
18
|
export declare function SegmentedControl(props: SegmentedControlProps): JSX.Element;
|
|
@@ -1,18 +1,33 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Icon } from "../icons/Icon.jsx";
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Segmented control — inset track, raised active segment. Switches views of the same data, applies instantly.
|
|
6
|
+
* options: string[] | { label, icon?, disabled? }[] value/onChange by label
|
|
7
|
+
* size sm 24 | md 32 | lg 36 — omit it to inherit the region's tier · iconOnly hides labels (label becomes aria-label / title)
|
|
8
|
+
* disabled greys the whole control · fullWidth stretches segments evenly
|
|
9
|
+
* Keyboard: ← → move between enabled segments.
|
|
10
|
+
*/
|
|
11
|
+
const tierIcon = { width: "var(--control-icon)", height: "var(--control-icon)" };
|
|
12
|
+
export function SegmentedControl({ options = [], value, onChange, size, iconOnly, disabled, fullWidth, style }) {
|
|
13
|
+
const opts = options.map((o) => (typeof o === "string" ? { label: o } : o));
|
|
14
|
+
const enabled = opts.filter((o) => !o.disabled);
|
|
15
|
+
const onKey = (e) => {
|
|
16
|
+
if (e.key !== "ArrowLeft" && e.key !== "ArrowRight" || disabled || !enabled.length) return;
|
|
17
|
+
e.preventDefault();
|
|
18
|
+
const i = enabled.findIndex((o) => o.label === value);
|
|
19
|
+
const n = e.key === "ArrowRight" ? enabled[(i + 1) % enabled.length] : enabled[(i - 1 + enabled.length) % enabled.length];
|
|
20
|
+
onChange && onChange(n.label);
|
|
21
|
+
};
|
|
7
22
|
return (
|
|
8
|
-
<div style={{ display: "inline-flex", padding: 2, gap: 2, background: "var(--bg-inset)", border: "1px solid var(--border-control)", borderRadius: "var(--radius-md)", boxSizing: "border-box", ...style }}>
|
|
9
|
-
{
|
|
10
|
-
const
|
|
11
|
-
const is = value === label;
|
|
23
|
+
<div role="tablist" data-size={size} aria-disabled={disabled || undefined} onKeyDown={onKey} style={{ display: fullWidth ? "flex" : "inline-flex", height: "var(--control-h)", padding: 2, gap: 2, background: "var(--bg-inset)", border: "1px solid var(--border-control)", borderRadius: "var(--radius-md)", boxSizing: "border-box", opacity: disabled ? .5 : 1, ...style }}>
|
|
24
|
+
{opts.map((o) => {
|
|
25
|
+
const is = value === o.label, off = disabled || o.disabled;
|
|
12
26
|
return (
|
|
13
|
-
<button key={label} type="button"
|
|
14
|
-
|
|
15
|
-
{
|
|
27
|
+
<button key={o.label} type="button" role="tab" aria-selected={is} aria-label={iconOnly ? o.label : undefined} title={iconOnly ? o.label : undefined} disabled={off} tabIndex={is ? 0 : -1} data-ink={is || off ? undefined : ""}
|
|
28
|
+
onClick={() => !off && onChange && onChange(o.label)}
|
|
29
|
+
style={{ height: "calc(var(--control-h) - 6px)", padding: iconOnly ? "0 calc(var(--control-px) - 4px)" : "0 calc(var(--control-px) - 2px)", flex: fullWidth ? 1 : "none", justifyContent: "center", display: "inline-flex", alignItems: "center", gap: 6, borderRadius: "var(--radius-sm)", border: "none", cursor: off ? "not-allowed" : "pointer", background: is ? "var(--bg-surface)" : "transparent", boxShadow: is ? "0 1px 2px rgba(0,0,0,.08)" : "none", fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--control-text)", lineHeight: "var(--control-leading)", letterSpacing: "var(--control-tracking)", color: is ? "var(--text-heading)" : "var(--ink, var(--text-secondary))", opacity: o.disabled && !disabled ? .45 : 1, whiteSpace: "nowrap", transition: "var(--t-hover)" }}>
|
|
30
|
+
{o.icon ? <Icon name={o.icon} size={16} style={tierIcon} /> : null}{iconOnly ? null : o.label}
|
|
16
31
|
</button>
|
|
17
32
|
);
|
|
18
33
|
})}
|
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { computed } from 'vue'
|
|
2
3
|
import Icon from '../icons/Icon.vue'
|
|
3
|
-
// Segmented control — inset track, raised active segment.
|
|
4
|
-
|
|
4
|
+
// Segmented control — inset track, raised active segment. Switches views of the same data, applies instantly.
|
|
5
|
+
// options: string[] | { label, icon?, disabled? }[] · v-model by label · size sm 24 | md 32 | lg 36 — omit it to inherit the region's tier
|
|
6
|
+
// iconOnly hides labels (label → aria-label/title) · disabled greys the control · fullWidth stretches segments · ← → keyboard.
|
|
7
|
+
const tierIcon = { width: 'var(--control-icon)', height: 'var(--control-icon)' }
|
|
8
|
+
const props = defineProps({ options: { type: Array, default: () => [] }, modelValue: String, size: String, iconOnly: Boolean, disabled: Boolean, fullWidth: Boolean, style: Object })
|
|
5
9
|
const emit = defineEmits(['update:modelValue'])
|
|
6
|
-
|
|
10
|
+
const opts = computed(() => props.options.map(o => typeof o === 'string' ? { label: o } : o))
|
|
11
|
+
const enabled = computed(() => opts.value.filter(o => !o.disabled))
|
|
12
|
+
const pick = (o) => { if (!(props.disabled || o.disabled)) emit('update:modelValue', o.label) }
|
|
13
|
+
function onKey(e) {
|
|
14
|
+
if ((e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') || props.disabled || !enabled.value.length) return
|
|
15
|
+
e.preventDefault()
|
|
16
|
+
const i = enabled.value.findIndex(o => o.label === props.modelValue), n = enabled.value.length
|
|
17
|
+
emit('update:modelValue', (e.key === 'ArrowRight' ? enabled.value[(i + 1) % n] : enabled.value[(i - 1 + n) % n]).label)
|
|
18
|
+
}
|
|
7
19
|
</script>
|
|
8
20
|
<template>
|
|
9
|
-
<div :style="{ display: 'inline-flex', padding:
|
|
10
|
-
<button v-for="o in
|
|
11
|
-
:style="{ height: (
|
|
12
|
-
<Icon v-if="
|
|
21
|
+
<div role="tablist" :data-size="size" :aria-disabled="disabled || undefined" @keydown="onKey" :style="{ display: fullWidth ? 'flex' : 'inline-flex', height: 'var(--control-h)', padding: '2px', gap: '2px', background: 'var(--bg-inset)', border: '1px solid var(--border-control)', borderRadius: 'var(--radius-md)', boxSizing: 'border-box', opacity: disabled ? .5 : 1, ...style }">
|
|
22
|
+
<button v-for="o in opts" :key="o.label" type="button" role="tab" :aria-selected="modelValue === o.label" :aria-label="iconOnly ? o.label : undefined" :title="iconOnly ? o.label : undefined" :disabled="disabled || o.disabled" :tabindex="modelValue === o.label ? 0 : -1" :data-ink="modelValue === o.label || disabled || o.disabled ? undefined : ''" @click="pick(o)"
|
|
23
|
+
:style="{ height: 'calc(var(--control-h) - 6px)', padding: iconOnly ? '0 calc(var(--control-px) - 4px)' : '0 calc(var(--control-px) - 2px)', flex: fullWidth ? 1 : 'none', justifyContent: 'center', display: 'inline-flex', alignItems: 'center', gap: '6px', borderRadius: 'var(--radius-sm)', border: 'none', cursor: (disabled || o.disabled) ? 'not-allowed' : 'pointer', background: modelValue === o.label ? 'var(--bg-surface)' : 'transparent', boxShadow: modelValue === o.label ? '0 1px 2px rgba(0,0,0,.08)' : 'none', fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-medium)', fontSize: 'var(--control-text)', lineHeight: 'var(--control-leading)', letterSpacing: 'var(--control-tracking)', color: modelValue === o.label ? 'var(--text-heading)' : 'var(--ink, var(--text-secondary))', opacity: o.disabled && !disabled ? .45 : 1, whiteSpace: 'nowrap', transition: 'var(--t-hover)' }">
|
|
24
|
+
<Icon v-if="o.icon" :name="o.icon" :size="16" :style="tierIcon" /><template v-if="!iconOnly">{{ o.label }}</template>
|
|
13
25
|
</button>
|
|
14
26
|
</div>
|
|
15
27
|
</template>
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
/** Underline tabs (Import/Export). Active: blue text + 2px blue underline on hairline baseline. */
|
|
2
|
+
/** Underline tabs (Import/Export). Active: blue text + 2px blue underline on hairline baseline. The bar is the region's bar height (sm 32 · md 40 · lg 44). */
|
|
3
3
|
export interface TabsProps {
|
|
4
4
|
tabs?: string[];
|
|
5
5
|
active?: string;
|
|
6
6
|
onChange?: (tab: string) => void;
|
|
7
|
+
/** Size tier. Omit to inherit the enclosing region's tier (the default). */
|
|
8
|
+
size?: "sm" | "md" | "lg";
|
|
7
9
|
style?: React.CSSProperties;
|
|
8
10
|
}
|
|
9
11
|
export declare function Tabs(props: TabsProps): JSX.Element;
|
|
10
|
-
/**
|
|
12
|
+
/** Lighter underline tabs for panels (Node Info / Calc Rules / ...), regular weight; an sm region gives the compact 32px/12px look. */
|
|
11
13
|
export declare function PanelTabs(props: TabsProps): JSX.Element;
|
|
12
|
-
/** Text pill filter tabs; active gets a
|
|
14
|
+
/** Text pill filter tabs at control height; active gets a tinted pill. */
|
|
13
15
|
export declare function PillTabs(props: TabsProps): JSX.Element;
|
package/components/tabs/Tabs.jsx
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
/** Underline tabs on a hairline baseline (Import/Export). Active = blue text + 2px blue underline. */
|
|
4
|
-
export function Tabs({ tabs = [], active, onChange, style }) {
|
|
3
|
+
/** Underline tabs on a hairline baseline (Import/Export). Active = blue text + 2px blue underline. The bar is the region's bar height (sm 32 · md 40 · lg 44) with the tier's control text; omit `size` to inherit. */
|
|
4
|
+
export function Tabs({ tabs = [], active, onChange, size, style }) {
|
|
5
5
|
return (
|
|
6
|
-
<div style={{ display: "flex", gap: 4, borderBottom: "1px solid var(--border-control)", ...style }}>
|
|
6
|
+
<div role="tablist" data-size={size} style={{ display: "flex", gap: 4, borderBottom: "1px solid var(--border-control)", ...style }}>
|
|
7
7
|
{tabs.map((t) => {
|
|
8
8
|
const is = t === active;
|
|
9
9
|
return (
|
|
10
|
-
<button key={t} type="button" onClick={() => onChange && onChange(t)}
|
|
11
|
-
style={{ background: "transparent", border: "none", cursor: "pointer", padding: "
|
|
10
|
+
<button key={t} type="button" role="tab" aria-selected={is} data-ink={is ? undefined : ""} onClick={() => onChange && onChange(t)}
|
|
11
|
+
style={{ background: "transparent", border: "none", cursor: "pointer", height: "var(--bar-h)", boxSizing: "border-box", padding: "0 var(--control-px)", marginBottom: -1, borderBottom: is ? "2px solid var(--action-primary)" : "2px solid transparent", fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--control-text)", lineHeight: "var(--control-leading)", letterSpacing: "var(--control-tracking)", color: is ? "var(--action-primary)" : "var(--ink, var(--text-body))", whiteSpace: "nowrap" }}>
|
|
12
12
|
{t}
|
|
13
13
|
</button>
|
|
14
14
|
);
|
|
@@ -17,15 +17,15 @@ export function Tabs({ tabs = [], active, onChange, style }) {
|
|
|
17
17
|
);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
/**
|
|
21
|
-
export function PanelTabs({ tabs = [], active, onChange, style }) {
|
|
20
|
+
/** Panel tabs (Node Info · Calc Rules · Output Fields · SQL Preview): a lighter underline tab bar at the region's bar height with regular-weight control text. Put the panel in an sm region for the compact 32px/12px look. */
|
|
21
|
+
export function PanelTabs({ tabs = [], active, onChange, size, style }) {
|
|
22
22
|
return (
|
|
23
|
-
<div style={{ display: "flex", borderBottom: "1px solid var(--border-subtle)", ...style }}>
|
|
23
|
+
<div role="tablist" data-size={size} style={{ display: "flex", borderBottom: "1px solid var(--border-subtle)", ...style }}>
|
|
24
24
|
{tabs.map((t) => {
|
|
25
25
|
const is = t === active;
|
|
26
26
|
return (
|
|
27
|
-
<button key={t} type="button" onClick={() => onChange && onChange(t)}
|
|
28
|
-
style={{ background: "transparent", border: "none", cursor: "pointer", padding: "
|
|
27
|
+
<button key={t} type="button" role="tab" aria-selected={is} data-ink={is ? undefined : ""} onClick={() => onChange && onChange(t)}
|
|
28
|
+
style={{ background: "transparent", border: "none", cursor: "pointer", height: "var(--bar-h)", boxSizing: "border-box", padding: "0 var(--control-px)", marginBottom: -1, borderBottom: is ? "2px solid var(--action-primary)" : "2px solid transparent", fontFamily: "var(--font-sans)", fontSize: "var(--control-text)", lineHeight: "var(--control-leading)", letterSpacing: "var(--control-tracking)", color: is ? "var(--action-primary)" : "var(--ink, var(--text-secondary))", whiteSpace: "nowrap" }}>
|
|
29
29
|
{t}
|
|
30
30
|
</button>
|
|
31
31
|
);
|
|
@@ -34,15 +34,15 @@ export function PanelTabs({ tabs = [], active, onChange, style }) {
|
|
|
34
34
|
);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
/** Text pill filter tabs (For Review · To be Submitted · For Approval). Active =
|
|
38
|
-
export function PillTabs({ tabs = [], active, onChange, style }) {
|
|
37
|
+
/** Text pill filter tabs (For Review · To be Submitted · For Approval). Active = tinted pill. Pills are control-height (sm 24 · md 32 · lg 36); omit `size` to inherit. */
|
|
38
|
+
export function PillTabs({ tabs = [], active, onChange, size, style }) {
|
|
39
39
|
return (
|
|
40
|
-
<div style={{ display: "flex", gap:
|
|
40
|
+
<div role="tablist" data-size={size} style={{ display: "flex", gap: "var(--control-gap)", ...style }}>
|
|
41
41
|
{tabs.map((t) => {
|
|
42
42
|
const is = t === active;
|
|
43
43
|
return (
|
|
44
|
-
<button key={t} type="button" onClick={() => onChange && onChange(t)}
|
|
45
|
-
style={{ background: is ? "var(--bg-active)" : "transparent", border: "none", cursor: "pointer", height:
|
|
44
|
+
<button key={t} type="button" role="tab" aria-selected={is} data-ink={is ? undefined : ""} data-wash={is ? undefined : ""} onClick={() => onChange && onChange(t)}
|
|
45
|
+
style={{ background: is ? "var(--bg-active)" : "var(--wash, transparent)", border: "none", cursor: "pointer", height: "var(--control-h)", padding: "0 var(--control-px)", borderRadius: "var(--radius-md)", fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--control-text)", lineHeight: "var(--control-leading)", letterSpacing: "var(--control-tracking)", color: is ? "var(--text-heading)" : "var(--ink, var(--text-secondary))", whiteSpace: "nowrap" }}>
|
|
46
46
|
{t}
|
|
47
47
|
</button>
|
|
48
48
|
);
|
package/components/tabs/Tabs.vue
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
// Underline tabs on a hairline baseline (Import/Export). Active = blue text + 2px blue underline.
|
|
3
|
-
defineProps({ tabs: { type: Array, default: () => [] }, active: String, style: Object })
|
|
2
|
+
// Underline tabs on a hairline baseline (Import/Export). Active = blue text + 2px blue underline. The bar is the region's bar height (sm 32 · md 40 · lg 44) with the tier's control text; omit `size` to inherit.
|
|
3
|
+
defineProps({ tabs: { type: Array, default: () => [] }, active: String, size: String, style: Object })
|
|
4
4
|
const emit = defineEmits(['change'])
|
|
5
5
|
</script>
|
|
6
6
|
<template>
|
|
7
|
-
<div :style="{ display: 'flex', gap:
|
|
8
|
-
<button v-for="t in tabs" :key="t" type="button" @click="emit('change', t)"
|
|
9
|
-
:style="{ background: 'transparent', border: 'none', cursor: 'pointer', padding: '
|
|
7
|
+
<div role="tablist" :data-size="size" :style="{ display: 'flex', gap: '4px', borderBottom: '1px solid var(--border-control)', ...style }">
|
|
8
|
+
<button v-for="t in tabs" :key="t" type="button" role="tab" :aria-selected="t === active" :data-ink="t === active ? undefined : ''" @click="emit('change', t)"
|
|
9
|
+
:style="{ background: 'transparent', border: 'none', cursor: 'pointer', height: 'var(--bar-h)', boxSizing: 'border-box', padding: '0 var(--control-px)', marginBottom: '-1px', borderBottom: t === active ? '2px solid var(--action-primary)' : '2px solid transparent', fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-medium)', fontSize: 'var(--control-text)', lineHeight: 'var(--control-leading)', letterSpacing: 'var(--control-tracking)', color: t === active ? 'var(--action-primary)' : 'var(--ink, var(--text-body))', whiteSpace: 'nowrap' }">{{ t }}</button>
|
|
10
10
|
</div>
|
|
11
11
|
</template>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
/** list/grid
|
|
2
|
+
/** list/grid icon toggle — two IconButtons at the region's tier (sm 24 · md 32 · lg 36), active gets the tinted wash. */
|
|
3
3
|
export interface ViewToggleProps {
|
|
4
4
|
value?: "list" | "grid";
|
|
5
|
+
/** Size tier. Omit to inherit the enclosing region's tier (the default). */
|
|
6
|
+
size?: "sm" | "md" | "lg";
|
|
5
7
|
onChange?: (v: "list" | "grid") => void;
|
|
6
8
|
style?: React.CSSProperties;
|
|
7
9
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { IconButton } from "../buttons/IconButton.jsx";
|
|
3
3
|
|
|
4
|
-
/** Two-state list/grid icon toggle (palette header). */
|
|
5
|
-
export function ViewToggle({ value = "grid", onChange, style }) {
|
|
4
|
+
/** Two-state list/grid icon toggle (palette header). Two IconButtons at the region's tier; omit `size` to inherit. */
|
|
5
|
+
export function ViewToggle({ value = "grid", onChange, size, style }) {
|
|
6
6
|
return (
|
|
7
|
-
<div style={{ display: "inline-flex", gap: 2, ...style }}>
|
|
8
|
-
<IconButton icon="list"
|
|
9
|
-
<IconButton icon="layout-grid"
|
|
7
|
+
<div data-size={size} style={{ display: "inline-flex", gap: 2, ...style }}>
|
|
8
|
+
<IconButton icon="list" active={value === "list"} onClick={() => onChange && onChange("list")} label="List view" />
|
|
9
|
+
<IconButton icon="layout-grid" active={value === "grid"} onClick={() => onChange && onChange("grid")} label="Grid view" />
|
|
10
10
|
</div>
|
|
11
11
|
);
|
|
12
12
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import IconButton from '../buttons/IconButton.vue'
|
|
3
|
-
// Two-state list/grid icon toggle (palette header).
|
|
4
|
-
defineProps({ modelValue: { type: String, default: 'grid' }, style: Object })
|
|
3
|
+
// Two-state list/grid icon toggle (palette header). Two IconButtons at the region's tier; omit `size` to inherit.
|
|
4
|
+
defineProps({ modelValue: { type: String, default: 'grid' }, size: String, style: Object })
|
|
5
5
|
const emit = defineEmits(['update:modelValue'])
|
|
6
6
|
</script>
|
|
7
7
|
<template>
|
|
8
|
-
<div :style="{ display: 'inline-flex', gap:
|
|
9
|
-
<IconButton icon="list"
|
|
10
|
-
<IconButton icon="layout-grid"
|
|
8
|
+
<div :data-size="size" :style="{ display: 'inline-flex', gap: '2px', ...style }">
|
|
9
|
+
<IconButton icon="list" :active="modelValue === 'list'" label="List view" @click="emit('update:modelValue', 'list')" />
|
|
10
|
+
<IconButton icon="layout-grid" :active="modelValue === 'grid'" label="Grid view" @click="emit('update:modelValue', 'grid')" />
|
|
11
11
|
</div>
|
|
12
12
|
</template>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Tab systems: `Tabs` (
|
|
1
|
+
Tab systems: `Tabs` (underline — page level), `PanelTabs` (lighter underline — config panel, put the panel in an sm region), `PillTabs` (pill filters), `ViewToggle` (list/grid icons). All read the region's size tier: bars are 32 / 40 / 44px, pills 24 / 32 / 36px.
|
|
2
2
|
|
|
3
3
|
```jsx
|
|
4
4
|
<Tabs tabs={["Import","Export"]} active={tab} onChange={setTab}/>
|
|
@@ -7,8 +7,10 @@ Tab systems: `Tabs` (13px underline — page level), `PanelTabs` (12px underline
|
|
|
7
7
|
<ViewToggle value={view} onChange={setView}/>
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
`SegmentedControl` (addition) for view/range switches
|
|
10
|
+
`SegmentedControl` (addition) for view/range switches — same data, instant; never a saved value and never page navigation. `iconOnly`, per-option `disabled`, `fullWidth`:
|
|
11
11
|
|
|
12
12
|
```jsx
|
|
13
13
|
<SegmentedControl options={[{label:"List",icon:"list"},{label:"Grid",icon:"layout-grid"}]} value={v} onChange={setV}/>
|
|
14
|
+
<SegmentedControl iconOnly options={[{icon:"table",label:"Table"},{icon:"chart-column",label:"Chart"}]} value={m} onChange={setM}/>
|
|
15
|
+
<SegmentedControl fullWidth options={["Overview","Details","History"]} value={t} onChange={setT}/>
|
|
14
16
|
```
|
package/keybricks.css
ADDED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keyfunc/keybricks-ds",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Keybricks design system —
|
|
3
|
+
"version": "2.1.1",
|
|
4
|
+
"description": "Keybricks design system — 352 design tokens, three size tiers and 117 UI components in React and Vue 3, source-only.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"sideEffects": [
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"default": "./components/index.js"
|
|
14
14
|
},
|
|
15
15
|
"./vue": "./components/_vue/index.mjs",
|
|
16
|
-
"./styles.css": "./
|
|
16
|
+
"./styles.css": "./keybricks.css",
|
|
17
|
+
"./keybricks.css": "./keybricks.css",
|
|
17
18
|
"./tokens": {
|
|
18
19
|
"types": "./tokens/tokens.d.ts",
|
|
19
20
|
"default": "./tokens/tokens.js"
|
|
@@ -31,7 +32,9 @@
|
|
|
31
32
|
"assets",
|
|
32
33
|
"_scripts",
|
|
33
34
|
"styles.css",
|
|
35
|
+
"keybricks.css",
|
|
34
36
|
"readme.md",
|
|
37
|
+
"readme.zh-CN.md",
|
|
35
38
|
"DESIGN.md",
|
|
36
39
|
"INTEGRATION.md",
|
|
37
40
|
"DEPLOY.md",
|