@keyfunc/keybricks-ds 2.1.1 → 2.3.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 +13 -4
- package/DESIGN.md +104 -19
- package/INTEGRATION.md +75 -20
- package/SKILL.md +11 -11
- package/_adherence.oxlintrc.json +28 -11
- package/_scripts/build-index.mjs +15 -4
- package/assets/icons/icon-index.js +1 -1
- package/assets/icons/icon-index.json +1 -1
- package/components/_cards/accordion.card.html +1 -1
- package/components/_cards/action-chip.card.html +11 -14
- package/components/_cards/activity.card.html +2 -2
- package/components/_cards/alert.card.html +2 -2
- package/components/_cards/app-chrome.card.html +1 -1
- package/components/_cards/banner.card.html +1 -1
- package/components/_cards/breadcrumb.card.html +4 -4
- package/components/_cards/button-1-base.card.html +23 -26
- package/components/_cards/button-2-states.card.html +14 -12
- package/components/_cards/button-3-sizes-icons.card.html +20 -19
- package/components/_cards/button-4-group.card.html +14 -31
- package/components/_cards/canvas-zoom-controls.card.html +1 -1
- package/components/_cards/cards-indicators.card.html +1 -1
- package/components/_cards/charts-1-sparkline.card.html +4 -4
- package/components/_cards/charts-10-gauge.card.html +2 -2
- 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 +3 -3
- package/components/_cards/charts-15-distribution.card.html +2 -2
- 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 +3 -3
- package/components/_cards/charts-20-sunburst.card.html +2 -2
- package/components/_cards/charts-21-worldmap.card.html +3 -3
- 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 +6 -6
- package/components/_cards/charts-4-barlist.card.html +2 -2
- package/components/_cards/charts-5-donut.card.html +2 -2
- 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 +3 -3
- package/components/_cards/charts-99-fullpage.card.html +1 -1
- package/components/_cards/checkbox.card.html +6 -3
- package/components/_cards/codeblock.card.html +2 -2
- package/components/_cards/combobox.card.html +6 -4
- package/components/_cards/context-menu.card.html +6 -4
- package/components/_cards/date-picker.card.html +8 -5
- package/components/_cards/diffvalue.card.html +2 -2
- package/components/_cards/divider.card.html +2 -2
- package/components/_cards/drawer.card.html +3 -3
- package/components/_cards/dropdown-menu.card.html +2 -2
- package/components/_cards/dropzone.card.html +5 -3
- package/components/_cards/empty-state.card.html +2 -2
- package/components/_cards/filter-bar.card.html +1 -1
- package/components/_cards/icon-button.card.html +14 -14
- package/components/_cards/icons-1-core.card.html +4 -4
- package/components/_cards/icons-2-feather.card.html +4 -4
- package/components/_cards/icons-3-unicons.card.html +3 -3
- package/components/_cards/input.card.html +5 -5
- package/components/_cards/kbd.card.html +1 -1
- package/components/_cards/keyvalue.card.html +1 -1
- package/components/_cards/listrow.card.html +1 -1
- package/components/_cards/loading.card.html +2 -2
- package/components/_cards/log-viewer.card.html +2 -2
- package/components/_cards/modal.card.html +1 -1
- package/components/_cards/multi-select.card.html +6 -4
- package/components/_cards/number-stepper.card.html +9 -6
- package/components/_cards/pagination.card.html +6 -4
- package/components/_cards/people.card.html +2 -2
- package/components/_cards/pipeline-node.card.html +8 -8
- package/components/_cards/pipeline-palette.card.html +2 -2
- package/components/_cards/radio.card.html +12 -7
- package/components/_cards/search.card.html +6 -6
- package/components/_cards/segmented-control.card.html +11 -10
- package/components/_cards/select.card.html +7 -3
- package/components/_cards/slider.card.html +2 -2
- package/components/_cards/smart-table.card.html +3 -3
- package/components/_cards/spreadsheet.card.html +2 -2
- package/components/_cards/stepper.card.html +2 -2
- package/components/_cards/table.card.html +79 -17
- package/components/_cards/tabs.card.html +6 -4
- package/components/_cards/tag.card.html +6 -6
- package/components/_cards/textarea.card.html +1 -1
- package/components/_cards/timeline.card.html +3 -3
- package/components/_cards/toast.card.html +7 -5
- package/components/_cards/toggles.card.html +14 -9
- package/components/_cards/tooltip.card.html +3 -3
- package/components/_cards/tree.card.html +2 -2
- package/components/_shared/card-kit.css +25 -0
- package/components/_shared/card-kit.js +50 -0
- 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-icons.js +1 -1
- package/components/_shared/src-navigation.js +1 -1
- package/components/_shared/src-tabs.js +1 -1
- package/components/_shared/view-source.js +3 -3
- package/components/_vue/index.mjs +7 -0
- package/components/buttons/ActionChip.d.ts +1 -1
- package/components/buttons/Button.d.ts +1 -1
- package/components/buttons/Button.jsx +1 -1
- package/components/buttons/Button.vue +1 -1
- package/components/buttons/IconButton.d.ts +1 -1
- package/components/buttons/IconButton.jsx +5 -3
- package/components/buttons/IconButton.vue +3 -2
- package/components/charts/Bar3D.jsx +1 -1
- package/components/charts/Bar3D.vue +2 -2
- package/components/charts/BarChart.jsx +3 -3
- package/components/charts/BarChart.vue +6 -6
- package/components/charts/BarList.jsx +3 -3
- package/components/charts/BarList.vue +3 -3
- package/components/charts/BoxPlot.vue +2 -2
- package/components/charts/BulletChart.jsx +5 -5
- package/components/charts/BulletChart.vue +5 -5
- package/components/charts/CandlestickChart.vue +3 -3
- package/components/charts/ChartKit.jsx +4 -3
- package/components/charts/ChartTooltip.vue +1 -1
- package/components/charts/ChordChart.jsx +1 -1
- package/components/charts/ChordChart.vue +2 -2
- package/components/charts/DonutChart.jsx +1 -1
- package/components/charts/DonutChart.vue +2 -2
- package/components/charts/FunnelChart.jsx +3 -3
- package/components/charts/FunnelChart.vue +4 -4
- package/components/charts/GanttChart.vue +1 -1
- package/components/charts/GaugeChart.jsx +2 -2
- package/components/charts/GaugeChart.vue +2 -2
- package/components/charts/HeatmapChart.jsx +1 -1
- package/components/charts/HeatmapChart.vue +1 -1
- package/components/charts/Histogram.jsx +2 -2
- package/components/charts/Histogram.vue +4 -4
- package/components/charts/LineChart.vue +2 -2
- package/components/charts/ParetoChart.jsx +1 -1
- package/components/charts/ParetoChart.vue +3 -3
- package/components/charts/Pie3D.jsx +1 -1
- package/components/charts/Pie3D.vue +2 -2
- package/components/charts/PlotGrid.vue +1 -1
- package/components/charts/RadarChart.vue +1 -1
- package/components/charts/Ribbon3D.jsx +1 -1
- package/components/charts/Ribbon3D.vue +2 -2
- package/components/charts/SankeyChart.jsx +1 -1
- package/components/charts/SankeyChart.vue +2 -2
- package/components/charts/Scatter3D.vue +1 -1
- package/components/charts/ScatterChart.jsx +1 -1
- package/components/charts/ScatterChart.vue +3 -3
- package/components/charts/Sparkline.jsx +1 -1
- package/components/charts/Sparkline.vue +1 -1
- package/components/charts/SunburstChart.vue +1 -1
- package/components/charts/Surface3D.jsx +1 -1
- package/components/charts/Surface3D.vue +2 -2
- package/components/charts/TreemapChart.jsx +1 -1
- package/components/charts/TreemapChart.vue +2 -2
- package/components/charts/WaterfallChart.jsx +1 -1
- package/components/charts/WaterfallChart.vue +5 -4
- package/components/charts/WorldMap.jsx +4 -4
- package/components/charts/WorldMap.vue +5 -5
- package/components/data/DiffValue.d.ts +1 -0
- package/components/data/DiffValue.jsx +1 -1
- package/components/data/DiffValue.vue +1 -1
- package/components/data/KeyValue.d.ts +1 -1
- package/components/data/KeyValue.jsx +2 -2
- package/components/data/KeyValue.vue +2 -2
- package/components/data/Pagination.jsx +2 -2
- package/components/data/Pagination.vue +1 -1
- package/components/data/SmartTable.jsx +5 -5
- package/components/data/SmartTable.vue +6 -6
- package/components/data/Spreadsheet.jsx +5 -5
- package/components/data/Spreadsheet.vue +6 -6
- package/components/data/Table.d.ts +58 -4
- package/components/data/Table.jsx +153 -15
- package/components/data/Table.vue +105 -15
- package/components/data/data.prompt.md +1 -1
- package/components/display/Avatar.jsx +2 -2
- package/components/display/Avatar.vue +1 -1
- package/components/display/AvatarGroup.vue +1 -1
- package/components/display/Badge.d.ts +4 -1
- package/components/display/Badge.jsx +10 -5
- package/components/display/IconTile.vue +9 -4
- package/components/display/Kbd.d.ts +1 -1
- package/components/display/Kbd.jsx +1 -1
- package/components/display/Kbd.vue +1 -1
- package/components/feedback/ActivityItem.jsx +1 -1
- package/components/feedback/Modal.jsx +1 -1
- package/components/feedback/Modal.vue +1 -1
- package/components/feedback/Timeline.vue +2 -2
- package/components/forms/Combobox.d.ts +1 -1
- package/components/forms/DatePicker.d.ts +1 -1
- package/components/forms/Input.d.ts +1 -1
- package/components/forms/Input.jsx +2 -2
- package/components/forms/Input.vue +1 -1
- package/components/forms/MultiSelect.d.ts +1 -1
- package/components/forms/NumberStepper.d.ts +1 -1
- package/components/forms/SearchInput.d.ts +1 -1
- package/components/forms/Select.d.ts +1 -1
- package/components/forms/Select.jsx +1 -1
- package/components/forms/Select.vue +1 -1
- package/components/forms/Slider.jsx +1 -1
- package/components/forms/Slider.vue +1 -1
- package/components/forms/Switch.jsx +3 -3
- package/components/forms/Switch.vue +11 -8
- package/components/forms/Textarea.vue +1 -1
- package/components/forms/input-base.js +1 -1
- package/components/icons/Icon.jsx +17 -1
- package/components/icons/Icon.prompt.md +2 -0
- package/components/icons/Icon.vue +1 -1
- package/components/icons/icon-paths.js +15 -0
- package/components/index.js +1 -1
- package/components/navigation/Breadcrumb.jsx +3 -7
- package/components/navigation/Breadcrumb.vue +2 -8
- package/components/navigation/Sidebar.jsx +3 -22
- package/components/navigation/Sidebar.vue +2 -7
- package/components/navigation/Tree.jsx +1 -1
- package/components/navigation/Tree.vue +9 -4
- package/components/navigation/nav-model.js +23 -0
- package/components/navigation/theme-store.js +9 -0
- package/components/tabs/PillTabs.vue +1 -1
- package/components/tabs/SegmentedControl.d.ts +1 -1
- package/components/tabs/SegmentedControl.jsx +1 -1
- package/components/tabs/SegmentedControl.vue +1 -1
- package/components/tabs/Tabs.jsx +1 -1
- package/components/tabs/ViewToggle.d.ts +1 -1
- package/package.json +2 -2
- package/readme.md +6 -5
- package/readme.zh-CN.md +6 -5
- package/tokens/alpha.css +3 -1
- package/tokens/colors.css +1 -1
- package/tokens/dark.css +1 -1
- package/tokens/layout.css +7 -5
- package/tokens/tokens.d.ts +22 -0
- package/tokens/tokens.js +39 -6
- package/tokens/tokens.json +90 -11
- package/tokens/typography.css +26 -9
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
<!-- @dsCard group="Components" viewport="
|
|
1
|
+
<!-- @dsCard group="Components" viewport="700x300" name="Tag" subtitle="Removable filter tags — distinct from Badge/ActionChip" -->
|
|
2
2
|
<!DOCTYPE html>
|
|
3
|
-
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css">
|
|
3
|
+
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css"><link rel="stylesheet" href="../_shared/card-kit.css">
|
|
4
4
|
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
|
|
5
5
|
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
|
|
6
6
|
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
7
7
|
<script src="../../_ds_bundle.js"></script>
|
|
8
8
|
<script src="../_shared/view-source.js"></script>
|
|
9
|
-
<
|
|
9
|
+
<script src="../_shared/card-kit.js"></script>
|
|
10
|
+
<style>body{margin:0;background:var(--bg-surface);padding:16px;font-family:var(--font-sans);box-sizing:border-box}.lbl{font-size:var(--text-xs);color:var(--text-muted);display:block;padding-bottom:8px}</style></head>
|
|
10
11
|
<body><div id="root"></div>
|
|
11
12
|
<script type="text/babel">
|
|
12
13
|
const { Tag } = window.KeybricksDesignSystem_71231a;
|
|
14
|
+
const { KBTiers: Tiers } = window;
|
|
13
15
|
function Sheet(){
|
|
14
16
|
const [tags,setTags]=React.useState(["Financial Settings","User Management","2026"]);
|
|
15
17
|
return <div style={{display:"flex",flexDirection:"column",gap:14}}>
|
|
@@ -19,9 +21,7 @@ function Sheet(){
|
|
|
19
21
|
<div><span className="lbl">Static, neutral & info tone</span>
|
|
20
22
|
<div style={{display:"flex",gap:6}}><Tag>Draft</Tag><Tag tone="info">Auto-tagged</Tag></div>
|
|
21
23
|
</div>
|
|
22
|
-
<div><span className="lbl">Size tiers — data-size on the region, the control inherits ·
|
|
23
|
-
<div style={{display:"flex",gap:16,alignItems:"center",flexWrap:"wrap"}}><div data-size="sm"><Tag onRemove={()=>{}}>Financial Settings</Tag></div><div data-size="md"><Tag onRemove={()=>{}}>Financial Settings</Tag></div><div data-size="lg"><Tag onRemove={()=>{}}>Financial Settings</Tag></div></div>
|
|
24
|
-
</div>
|
|
24
|
+
<div style={{gridColumn:"1 / -1",display:"flex",flexDirection:"column",gap:8}}><span className="lbl">Size tiers — data-size on the region, the control inherits it</span><Tiers heads={{sm:"sm · 20",md:"md · 24",lg:"lg · 28"}} init={true} render={(t,l,v,set)=>v?<Tag onRemove={()=>set(false)}>{l==="en"?"Financial Settings":"财务设置"}</Tag>:<button type="button" onClick={()=>set(true)} style={{border:"none",background:"none",padding:0,cursor:"pointer",font:"inherit",fontSize:"var(--control-text)",color:"var(--link)"}}>{l==="en"?"Undo":"撤销"}</button>}/></div>
|
|
25
25
|
</div>;
|
|
26
26
|
}
|
|
27
27
|
ReactDOM.createRoot(document.getElementById("root")).render(<Sheet/>);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!-- @dsCard group="Components" viewport="924x520" name="Textarea" subtitle="Default · character count · over the limit · disabled" -->
|
|
2
2
|
<!DOCTYPE html>
|
|
3
|
-
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css">
|
|
3
|
+
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css"><link rel="stylesheet" href="../_shared/card-kit.css">
|
|
4
4
|
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
|
|
5
5
|
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
|
|
6
6
|
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
<!-- @dsCard group="Components" viewport="
|
|
1
|
+
<!-- @dsCard group="Components" viewport="700x350" name="Timeline" subtitle="Vertical activity timeline — toned icon nodes on a hairline spine" -->
|
|
2
2
|
<!DOCTYPE html>
|
|
3
|
-
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css">
|
|
3
|
+
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css"><link rel="stylesheet" href="../_shared/card-kit.css">
|
|
4
4
|
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
|
|
5
5
|
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
|
|
6
6
|
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
7
7
|
<script src="../../_ds_bundle.js"></script>
|
|
8
8
|
<script src="../_shared/view-source.js"></script>
|
|
9
|
-
<style>body{margin:0;background:var(--bg-surface);padding:16px;font-family:var(--font-sans);box-sizing:border-box}.g{display:grid;grid-template-columns:1fr 1fr;gap:24px}.lbl{font-size:
|
|
9
|
+
<style>body{margin:0;background:var(--bg-surface);padding:16px;font-family:var(--font-sans);box-sizing:border-box}.g{display:grid;grid-template-columns:1fr 1fr;gap:24px}.lbl{font-size:var(--text-xs);color:var(--text-muted);display:block;padding-bottom:10px}</style></head>
|
|
10
10
|
<body><div id="root"></div>
|
|
11
11
|
<script type="text/babel">
|
|
12
12
|
const { Timeline, Tag } = window.KeybricksDesignSystem_71231a;
|
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
<!-- @dsCard group="Components" viewport="700x450" name="Toast" subtitle="Tones · with/without meta · live ToastStack demo" -->
|
|
2
2
|
<!DOCTYPE html>
|
|
3
|
-
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css">
|
|
3
|
+
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css"><link rel="stylesheet" href="../_shared/card-kit.css">
|
|
4
4
|
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
|
|
5
5
|
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
|
|
6
6
|
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
7
7
|
<script src="../../_ds_bundle.js"></script>
|
|
8
8
|
<script src="../_shared/view-source.js"></script>
|
|
9
|
+
<script src="../_shared/card-kit.js"></script>
|
|
9
10
|
<style>body{margin:0;background:var(--bg-surface);padding:16px;font-family:var(--font-sans);box-sizing:border-box}.col{display:flex;flex-direction:column;gap:10px;max-width:380px}</style></head>
|
|
10
11
|
<body><div id="root"></div>
|
|
11
12
|
<script type="text/babel">
|
|
12
13
|
const { Toast, ToastStack, Button } = window.KeybricksDesignSystem_71231a;
|
|
14
|
+
const { KBLive: Live } = window;
|
|
13
15
|
function Sheet(){
|
|
14
16
|
const [toasts,setToasts]=React.useState([]);
|
|
15
17
|
const notify=(tone,title,meta)=>{const id=Date.now()+Math.random();setToasts(s=>[...s,{id,tone,title,meta}]);setTimeout(()=>setToasts(s=>s.filter(t=>t.id!==id)),3200);};
|
|
16
18
|
return <div>
|
|
17
19
|
<div className="col">
|
|
18
|
-
<Toast tone="success" title="Import completed" meta="3 configurations applied" onClose={()=>{}}
|
|
19
|
-
<Toast tone="danger" title="Report generation failed" meta="Q1 Summary • retry available" onClose={()=>{}}
|
|
20
|
-
<Toast tone="warning" title="4 configurations differ" meta="Review before continuing" onClose={()=>{}}
|
|
21
|
-
<Toast tone="info" title="Sync started" onClose={()=>{}}
|
|
20
|
+
<Live init={true}>{(v,set)=>v?<Toast tone="success" title="Import completed" meta="3 configurations applied" onClose={()=>set(false)}/>:<button type="button" onClick={()=>set(true)} style={{alignSelf:"flex-start",border:"none",background:"none",padding:0,cursor:"pointer",font:"inherit",fontSize:"var(--text-xs)",color:"var(--link)"}}>Show again</button>}</Live>
|
|
21
|
+
<Live init={true}>{(v,set)=>v?<Toast tone="danger" title="Report generation failed" meta="Q1 Summary • retry available" onClose={()=>set(false)}/>:<button type="button" onClick={()=>set(true)} style={{alignSelf:"flex-start",border:"none",background:"none",padding:0,cursor:"pointer",font:"inherit",fontSize:"var(--text-xs)",color:"var(--link)"}}>Show again</button>}</Live>
|
|
22
|
+
<Live init={true}>{(v,set)=>v?<Toast tone="warning" title="4 configurations differ" meta="Review before continuing" onClose={()=>set(false)}/>:<button type="button" onClick={()=>set(true)} style={{alignSelf:"flex-start",border:"none",background:"none",padding:0,cursor:"pointer",font:"inherit",fontSize:"var(--text-xs)",color:"var(--link)"}}>Show again</button>}</Live>
|
|
23
|
+
<Live init={true}>{(v,set)=>v?<Toast tone="info" title="Sync started" onClose={()=>set(false)}/>:<button type="button" onClick={()=>set(true)} style={{alignSelf:"flex-start",border:"none",background:"none",padding:0,cursor:"pointer",font:"inherit",fontSize:"var(--text-xs)",color:"var(--link)"}}>Show again</button>}</Live>
|
|
22
24
|
<Toast tone="success" title="Saved" />
|
|
23
25
|
</div>
|
|
24
26
|
<div style={{display:"flex",gap:8,paddingTop:16}}>
|
|
@@ -1,32 +1,37 @@
|
|
|
1
|
-
<!-- @dsCard group="Components" viewport="
|
|
1
|
+
<!-- @dsCard group="Components" viewport="700x1670" name="Toggle Switch" subtitle="Binary settings pill — sizes · semantic red→green · glyph knobs · inline text · captions · async loading" -->
|
|
2
2
|
<!DOCTYPE html>
|
|
3
|
-
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css">
|
|
3
|
+
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css"><link rel="stylesheet" href="../_shared/card-kit.css">
|
|
4
4
|
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
|
|
5
5
|
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
|
|
6
6
|
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
7
7
|
<script src="../../_ds_bundle.js"></script>
|
|
8
8
|
<script src="../_shared/view-source.js"></script>
|
|
9
|
-
<
|
|
9
|
+
<script src="../_shared/card-kit.js"></script>
|
|
10
|
+
<style>body{margin:0;padding:20px 24px;font-family:var(--font-sans);background:var(--bg-surface)}.sec{font-size:var(--text-xs);font-weight:600;color:var(--text-muted);padding:18px 0 6px;border-top:1px solid var(--border-subtle);margin-top:14px}.sec:first-child{border-top:none;margin-top:0;padding-top:0}.case{display:grid;grid-template-columns:230px 1fr;align-items:center;gap:20px;min-height:36px;padding:5px 0}.k{font-size:var(--text-xs);color:var(--text-secondary);font-family:var(--font-sans)}.v{display:flex;align-items:center;gap:16px;flex-wrap:wrap}.cap{font-size:var(--text-xs);color:var(--text-muted)}a{color:var(--link)}a:hover{color:var(--link-hover)}.kb-h-gap{margin:28px 0 12px}.kb-h-gap:first-child{margin-top:0}</style>
|
|
10
11
|
</head><body><div id="root"></div>
|
|
11
12
|
<script type="text/babel">
|
|
12
13
|
const { Switch } = window.KeybricksDesignSystem_71231a;
|
|
14
|
+
const { KBTiers: Tiers } = window;
|
|
13
15
|
const wait = (ms, ok = true) => new Promise(r => setTimeout(() => r(ok), ms));
|
|
14
16
|
const Case = ({ k, children }) => <div className="case"><span className="k">{k}</span><div className="v">{children}</div></div>;
|
|
15
17
|
function Sheet() {
|
|
16
18
|
const [v, set] = React.useState({});
|
|
17
19
|
const b = (k, d = false) => ({ checked: v[k] ?? d, onChange: n => set(s => ({ ...s, [k]: n })) });
|
|
18
20
|
return <div>
|
|
19
|
-
<div className="
|
|
21
|
+
<div className="kb-h kb-h-gap">Sizes & states — sm · md · lg</div>
|
|
20
22
|
<Case k="on"><Switch size="sm" {...b("s1", true)} /><Switch {...b("s2", true)} /><Switch size="lg" {...b("s3", true)} /></Case>
|
|
21
23
|
<Case k="off"><Switch size="sm" {...b("s4")} /><Switch {...b("s5")} /><Switch size="lg" {...b("s6")} /></Case>
|
|
22
24
|
<Case k="disabled"><Switch size="sm" checked disabled /><Switch checked disabled /><Switch size="lg" checked disabled /></Case>
|
|
23
25
|
<Case k="label (settings row)"><Switch size="sm" label="Compact rows" {...b("s7", true)} /><Switch label="Debug Mode" {...b("s8", true)} /><Switch size="lg" label="Auto-run" {...b("s9", true)} /></Case>
|
|
24
26
|
|
|
25
|
-
<div className="
|
|
27
|
+
<div className="kb-h kb-h-gap">Size tiers — Latin and CJK labels</div>
|
|
28
|
+
<Tiers init={true} render={(t,l,v,set)=><Switch label={l==="en"?"Compact rows":"紧凑行高"} checked={v} onChange={set}/>}/>
|
|
29
|
+
|
|
30
|
+
<div className="kb-h kb-h-gap">Semantic tone — danger off → success on</div>
|
|
26
31
|
<Case k='tone="semantic" · on'><Switch size="sm" tone="semantic" {...b("t1", true)} /><Switch tone="semantic" {...b("t2", true)} /><Switch size="lg" tone="semantic" {...b("t3", true)} /></Case>
|
|
27
32
|
<Case k="off"><Switch size="sm" tone="semantic" {...b("t4")} /><Switch tone="semantic" {...b("t5")} /><Switch size="lg" tone="semantic" {...b("t6")} /></Case>
|
|
28
33
|
|
|
29
|
-
<div className="
|
|
34
|
+
<div className="kb-h kb-h-gap">Glyph in the knob — md · lg only (sm knob is 12px, too small for a glyph)</div>
|
|
30
35
|
<Case k="knobIcon check"><Switch knobIcon="check" {...b("g1", true)} /><Switch size="lg" knobIcon="check" {...b("g2", true)} /></Case>
|
|
31
36
|
<Case k="knobIcon {check, x}"><Switch knobIcon={{ on: "check", off: "x" }} {...b("g3")} /><Switch size="lg" knobIcon={{ on: "check", off: "x" }} {...b("g4")} /></Case>
|
|
32
37
|
<Case k="knobIcon {sun, moon}"><Switch knobIcon={{ on: "sun", off: "moon" }} {...b("g5", true)} /><Switch size="lg" knobIcon={{ on: "sun", off: "moon" }} {...b("g6", true)} /></Case>
|
|
@@ -34,17 +39,17 @@ function Sheet() {
|
|
|
34
39
|
<Case k="knobText — one CJK character {开, 关}"><Switch knobText={{ on: "开", off: "关" }} {...b("g9")} /><Switch size="lg" knobText={{ on: "开", off: "关" }} {...b("g10")} /></Case>
|
|
35
40
|
<Case k="semantic + knobIcon"><Switch tone="semantic" knobIcon={{ on: "check", off: "x" }} {...b("g11", true)} /><Switch size="lg" tone="semantic" knobIcon={{ on: "check", off: "x" }} {...b("g12", true)} /></Case>
|
|
36
41
|
|
|
37
|
-
<div className="
|
|
42
|
+
<div className="kb-h kb-h-gap">Text inside the pill — md · lg only</div>
|
|
38
43
|
<Case k="ON / OFF"><Switch insideOn="ON" insideOff="OFF" {...b("i1", true)} /><Switch size="lg" insideOn="ON" insideOff="OFF" {...b("i2", true)} /></Case>
|
|
39
44
|
<Case k="开 / 关"><Switch insideOn="开" insideOff="关" {...b("i3")} /><Switch size="lg" insideOn="开" insideOff="关" {...b("i4")} /></Case>
|
|
40
45
|
<Case k="semantic · Y / N"><Switch tone="semantic" insideOn="Y" insideOff="N" {...b("i5", true)} /><Switch size="lg" tone="semantic" insideOn="Y" insideOff="N" {...b("i6", true)} /></Case>
|
|
41
46
|
|
|
42
|
-
<div className="
|
|
47
|
+
<div className="kb-h kb-h-gap">Captions beside — sm · md · lg (active side reads heading)</div>
|
|
43
48
|
<Case k="labelOn"><Switch size="sm" labelOn="Enabled" {...b("l1", true)} /><Switch labelOn="Enabled" {...b("l2", true)} /><Switch size="lg" labelOn="Enabled" {...b("l3", true)} /></Case>
|
|
44
49
|
<Case k="labelOff + labelOn"><Switch size="sm" labelOff="Monthly" labelOn="Annual" {...b("l4")} /><Switch labelOff="Monthly" labelOn="Annual" {...b("l5")} /><Switch size="lg" labelOff="Monthly" labelOn="Annual" {...b("l6")} /></Case>
|
|
45
50
|
<Case k="semantic · Off / On"><Switch size="sm" tone="semantic" labelOff="Off" labelOn="On" {...b("l7", true)} /><Switch tone="semantic" labelOff="Off" labelOn="On" {...b("l8", true)} /><Switch size="lg" tone="semantic" labelOff="Off" labelOn="On" {...b("l9", true)} /></Case>
|
|
46
51
|
|
|
47
|
-
<div className="
|
|
52
|
+
<div className="kb-h kb-h-gap">Loading — sm · md · lg</div>
|
|
48
53
|
<Case k="loading · on"><Switch size="sm" checked loading /><Switch checked loading /><Switch size="lg" checked loading /></Case>
|
|
49
54
|
<Case k="loading · off"><Switch size="sm" loading /><Switch loading /><Switch size="lg" loading /></Case>
|
|
50
55
|
<Case k="semantic · loading"><Switch size="sm" tone="semantic" checked loading /><Switch tone="semantic" checked loading /><Switch size="lg" tone="semantic" checked loading /></Case>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<!-- @dsCard group="Components" viewport="700x360" name="Tooltip" subtitle="Placements — top · bottom · left · right, on icon and text triggers" -->
|
|
2
2
|
<!DOCTYPE html>
|
|
3
|
-
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css">
|
|
3
|
+
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css"><link rel="stylesheet" href="../_shared/card-kit.css">
|
|
4
4
|
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
|
|
5
5
|
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
|
|
6
6
|
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
7
7
|
<script src="../../_ds_bundle.js"></script>
|
|
8
8
|
<script src="../_shared/view-source.js"></script>
|
|
9
|
-
<style>body{margin:0;background:var(--bg-surface);padding:16px 16px 60px;font-family:var(--font-sans);box-sizing:border-box}.row{display:flex;gap:24px;align-items:center;margin-bottom:20px}.lbl{width:64px;flex-shrink:0;font-size:
|
|
10
|
-
<body><div id="root"></div>
|
|
9
|
+
<style>body{margin:0;background:var(--bg-surface);padding:16px 16px 60px;font-family:var(--font-sans);box-sizing:border-box}.row{display:flex;gap:24px;align-items:center;margin-bottom:20px}.lbl{width:64px;flex-shrink:0;font-size:var(--text-xs);color:var(--text-muted)}</style></head>
|
|
10
|
+
<body data-pad="tall"><div id="root"></div>
|
|
11
11
|
<script type="text/babel">
|
|
12
12
|
const { Tooltip, Button, IconButton } = window.KeybricksDesignSystem_71231a;
|
|
13
13
|
function Sheet(){return <div>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<!-- @dsCard group="Components" viewport="700x2110" name="Tree" subtitle="Cascading checkboxes · disabled nodes · lines · async load · search · drag · keyboard" -->
|
|
2
2
|
<!DOCTYPE html>
|
|
3
|
-
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css">
|
|
3
|
+
<html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css"><link rel="stylesheet" href="../../tokens/hover.css"><link rel="stylesheet" href="../_shared/card-kit.css">
|
|
4
4
|
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
|
|
5
5
|
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
|
|
6
6
|
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
7
7
|
<script src="../../_ds_bundle.js"></script>
|
|
8
8
|
<script src="../_shared/view-source.js"></script>
|
|
9
|
-
<style>body{margin:0;background:var(--bg-surface);padding:16px;font-family:var(--font-sans);box-sizing:border-box}.g{display:grid;grid-template-columns:1fr 1fr;gap:24px 28px}.lbl{font-size:
|
|
9
|
+
<style>body{margin:0;background:var(--bg-surface);padding:16px;font-family:var(--font-sans);box-sizing:border-box}.g{display:grid;grid-template-columns:1fr 1fr;gap:24px 28px}.lbl{font-size:var(--text-xs);color:var(--text-muted);display:block;padding-bottom:8px}.hint{font-size:var(--text-xs);line-height:16px;color:var(--text-secondary);padding-top:7px}.hint code{font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-body)}.note{grid-column:1/-1;border-top:1px solid var(--border-subtle);padding-top:12px;font-size:var(--text-xs);line-height:17px;color:var(--text-secondary)}.note code{font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-body)}.note strong{color:var(--text-heading);font-weight:var(--weight-medium)}</style></head>
|
|
10
10
|
<body><div id="root"></div>
|
|
11
11
|
<script type="text/babel">
|
|
12
12
|
const { Tree, SearchInput, IconButton, Icon } = window.KeybricksDesignSystem_71231a;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* Specimen layout for component cards — one grid for every card, so labels, rows and tier demos line up.
|
|
2
|
+
Not a token file and not part of the package: cards link it next to styles.css. */
|
|
3
|
+
body{margin:0;background:var(--bg-surface);padding:24px;font-family:var(--font-sans);color:var(--text-body);box-sizing:border-box}
|
|
4
|
+
.kb-sheet{display:flex;flex-direction:column;gap:28px}
|
|
5
|
+
.kb-sec{display:flex;flex-direction:column;gap:12px}
|
|
6
|
+
.kb-h{margin:0;font-size:var(--text-xs);line-height:var(--leading-xs);font-weight:600;color:var(--text-muted);padding-bottom:8px;border-bottom:1px solid var(--border-subtle)}
|
|
7
|
+
.kb-row{display:grid;grid-template-columns:120px minmax(0,1fr);column-gap:16px;align-items:center;min-height:32px}
|
|
8
|
+
.kb-k{font-size:var(--text-xs);line-height:var(--leading-xs);color:var(--text-secondary);font-family:var(--font-sans);font-variant-numeric:tabular-nums}
|
|
9
|
+
.kb-v{display:flex;flex-wrap:wrap;gap:12px;align-items:center;min-width:0}
|
|
10
|
+
.kb-note{margin:0;font-size:var(--text-xs);line-height:18px;color:var(--text-secondary);text-wrap:pretty}
|
|
11
|
+
.kb-note code,.kb-code{font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-body)}
|
|
12
|
+
.kb-tiers{display:grid;grid-template-columns:120px repeat(3,max-content);gap:12px 24px;align-items:center}
|
|
13
|
+
.kb-th{font-size:var(--text-xs);line-height:var(--leading-xs);color:var(--text-muted);font-family:var(--font-sans);font-variant-numeric:tabular-nums}
|
|
14
|
+
.kb-grid{display:grid;gap:12px 20px;align-items:center}
|
|
15
|
+
/* ── Legacy card markup, normalized to the same rhythm (outranks each card's own one-class rules) ── */
|
|
16
|
+
html body{padding:24px}
|
|
17
|
+
html body[data-pad="tall"]{padding-bottom:60px} /* room for popovers that open below the last row */
|
|
18
|
+
body .sh{margin:0 0 12px;font-size:var(--text-xs);line-height:var(--leading-xs);font-weight:600;color:var(--text-muted);padding-bottom:8px;border-bottom:1px solid var(--border-subtle)}
|
|
19
|
+
body .lbl{font-size:var(--text-xs);line-height:var(--leading-xs);color:var(--text-secondary)}
|
|
20
|
+
body :not(.row)>.lbl{padding-bottom:8px}
|
|
21
|
+
body .hint,body .note{font-size:var(--text-xs);line-height:18px;color:var(--text-secondary)}
|
|
22
|
+
body .g{gap:20px 24px}
|
|
23
|
+
body .sec{padding-bottom:28px}
|
|
24
|
+
body .sec:last-child{padding-bottom:0}
|
|
25
|
+
body .case .k{font-size:var(--text-xs);line-height:var(--leading-xs);color:var(--text-secondary);font-family:var(--font-sans)}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Specimen helpers for component cards (plain JS, no JSX). Load after React.
|
|
2
|
+
// <KBSec title="…" note="…">rows</KBSec> a section with a hairline heading
|
|
3
|
+
// <KBRow k="primary">controls</KBRow> a label column + a wrapping control row
|
|
4
|
+
// <KBTiers render={(tier, lang) => …}/> sm · md · lg across, a Latin row and a CJK row
|
|
5
|
+
// <KBTiers stack …/> wide controls: one row per tier, Latin and CJK side by side
|
|
6
|
+
// <KBTiers init={(lang) => v} render={(tier, lang, value, setValue) => …}/>
|
|
7
|
+
// every cell keeps its own state, so each demo is live on its own
|
|
8
|
+
// The CJK row sets lang="zh-CN" on each cell, so the 13px sm text and the regular sm weight apply.
|
|
9
|
+
(function () {
|
|
10
|
+
var h = function () { return window.React.createElement.apply(null, arguments); };
|
|
11
|
+
var HEADS = { sm: "sm · 28", md: "md · 32", lg: "lg · 40" };
|
|
12
|
+
function KBSec(p) {
|
|
13
|
+
return h("section", { className: "kb-sec", style: p.style },
|
|
14
|
+
p.title ? h("h3", { className: "kb-h" }, p.title) : null, p.children,
|
|
15
|
+
p.note ? h("p", { className: "kb-note" }, p.note) : null);
|
|
16
|
+
}
|
|
17
|
+
function KBRow(p) {
|
|
18
|
+
return h("div", { className: "kb-row" }, h("span", { className: "kb-k" }, p.k), h("div", { className: "kb-v", style: p.style }, p.children));
|
|
19
|
+
}
|
|
20
|
+
function TierCell(p) {
|
|
21
|
+
var st = window.React.useState(function () { return typeof p.init === "function" ? p.init(p.lang) : p.init; });
|
|
22
|
+
return h("div", { "data-size": p.tier, lang: p.l, style: { display: "flex", alignItems: p.align || "center", gap: 8, minWidth: 0 } }, p.render(p.tier, p.lang, st[0], st[1]));
|
|
23
|
+
}
|
|
24
|
+
function KBTiers(p) {
|
|
25
|
+
var heads = Object.assign({}, HEADS, p.heads || {});
|
|
26
|
+
var rows = p.cjk === false ? [["Latin", "en"]] : [["Latin", "en"], ["CJK · 中文", "zh-CN"]];
|
|
27
|
+
var cell = function (t, l, k) { return h(TierCell, { key: k, tier: t, l: l, lang: l === "en" ? "en" : "zh", init: p.init, render: p.render, align: p.align }); };
|
|
28
|
+
if (p.stack) {
|
|
29
|
+
var sc = [h("span", { key: "h0" })];
|
|
30
|
+
rows.forEach(function (r) { sc.push(h("span", { key: "h" + r[1], className: "kb-th" }, r[0])); });
|
|
31
|
+
["sm", "md", "lg"].forEach(function (t) {
|
|
32
|
+
sc.push(h("span", { key: "r" + t, className: "kb-th" }, heads[t]));
|
|
33
|
+
rows.forEach(function (r) { sc.push(cell(t, r[1], t + r[1])); });
|
|
34
|
+
});
|
|
35
|
+
return h("div", { className: "kb-tiers", style: Object.assign({ gridTemplateColumns: "120px repeat(" + rows.length + ",max-content)" }, p.style) }, sc);
|
|
36
|
+
}
|
|
37
|
+
var cells = [h("span", { key: "h0" })];
|
|
38
|
+
["sm", "md", "lg"].forEach(function (t) { cells.push(h("span", { key: "h" + t, className: "kb-th" }, heads[t])); });
|
|
39
|
+
rows.forEach(function (r) {
|
|
40
|
+
cells.push(h("span", { key: r[1], className: "kb-k" }, r[0]));
|
|
41
|
+
["sm", "md", "lg"].forEach(function (t) {
|
|
42
|
+
cells.push(cell(t, r[1], r[1] + t));
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
return h("div", { className: "kb-tiers", style: p.style }, cells);
|
|
46
|
+
}
|
|
47
|
+
// <KBLive init={v}>{(value, setValue) => …}</KBLive> — local state for a single live demo
|
|
48
|
+
function KBLive(p) { var st = window.React.useState(p.init); return p.children(st[0], st[1]); }
|
|
49
|
+
window.KBSec = KBSec; window.KBRow = KBRow; window.KBTiers = KBTiers; window.KBLive = KBLive;
|
|
50
|
+
})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
window.__KB_SRC__=Object.assign(window.__KB_SRC__||{},{"buttons/ActionChip.jsx":"import React from \"react\";\n\nconst chipTones = {\n success: { background: \"var(--success-bg)\", color: \"var(--success-text)\" },\n warning: { background: \"var(--warning-bg)\", color: \"var(--warning-text)\" },\n neutral: { background: \"var(--bg-hover)\", color: \"var(--text-body)\" },\n info: { background: \"var(--info-bg)\", color: \"var(--action-primary)\" },\n danger: { background: \"var(--danger-bg)\", color: \"var(--danger-text)\" },\n};\n\n/** Tinted bulk-action chip (\"Mark as New\", \"Mark as Overwrite\", \"Skip Selected\"). A control: it takes the region's tier height and text; `size` overrides it. */\nexport function ActionChip({ tone = \"neutral\", size, children, onClick, style }) {\n const [hover, setHover] = React.useState(false);\n return (\n <button type=\"button\" data-size={size} onClick={onClick} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}\n style={{ height: \"var(--control-h)\", padding: \"0 var(--control-px)\", borderRadius: \"var(--radius-md)\", border: \"none\", cursor: \"pointer\", fontFamily: \"var(--font-sans)\", fontWeight: \"var(--weight-medium)\", fontSize: \"var(--control-text)\", lineHeight: \"var(--control-leading)\", letterSpacing: \"var(--control-tracking)\", display: \"inline-flex\", alignItems: \"center\", filter: hover ? \"brightness(1.06) saturate(1.05)\" : \"none\", transition: \"var(--t-hover),filter var(--dur-fast) var(--ease-out)\", ...chipTones[tone], ...style }}>\n {children}\n </button>\n );\n}\n","buttons/ActionChip.vue":"<script setup>\nimport { ref, computed } from 'vue'\nconst chipTones = {\n success: { background: 'var(--success-bg)', color: 'var(--success-text)' },\n warning: { background: 'var(--warning-bg)', color: 'var(--warning-text)' },\n neutral: { background: 'var(--bg-hover)', color: 'var(--text-body)' },\n info: { background: 'var(--info-bg)', color: 'var(--action-primary)' },\n danger: { background: 'var(--danger-bg)', color: 'var(--danger-text)' },\n}\n// Tinted bulk-action chip (\"Mark as New\", \"Mark as Overwrite\", \"Skip Selected\"). A control: it takes the region's tier height and text; `size` overrides it.\nconst props = defineProps({ tone: { type: String, default: 'neutral' }, size: String, style: Object })\ndefineEmits(['click'])\nconst hover = ref(false)\nconst s = computed(() => ({ height: 'var(--control-h)', padding: '0 var(--control-px)', borderRadius: 'var(--radius-md)', border: 'none', cursor: 'pointer', fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-medium)', fontSize: 'var(--control-text)', lineHeight: 'var(--control-leading)', letterSpacing: 'var(--control-tracking)', display: 'inline-flex', alignItems: 'center', filter: hover.value ? 'brightness(1.06) saturate(1.05)' : 'none', transition: 'var(--t-hover),filter var(--dur-fast) var(--ease-out)', ...chipTones[props.tone], ...props.style }))\n</script>\n<template>\n <button type=\"button\" :data-size=\"size\" @click=\"$emit('click')\" @mouseenter=\"hover = true\" @mouseleave=\"hover = false\" :style=\"s\"><slot /></button>\n</template>\n","buttons/Button.jsx":"import React from \"react\";\nimport { Icon } from \"../icons/Icon.jsx\";\n\n/* Every dimension comes from the size tier the button sits in (tokens/layout.css): height, text, icon and padding\n switch together when a region declares data-size=\"sm\" | \"md\" | \"lg\". A `size` prop only stamps that attribute on\n the button itself — the default is to inherit, so siblings in one bar can never disagree. */\nconst btnBase = { display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\", gap: 6, height: \"var(--control-h)\", padding: \"0 var(--control-px)\", borderRadius: \"var(--radius-md)\", fontFamily: \"var(--font-sans)\", fontWeight: \"var(--weight-regular)\", fontSize: \"var(--control-text)\", lineHeight: \"var(--control-leading)\", letterSpacing: \"var(--control-tracking)\", border: \"1px solid transparent\", cursor: \"pointer\", whiteSpace: \"nowrap\", boxSizing: \"border-box\", background: \"transparent\", transition: \"var(--t-hover)\" };\nconst tierIcon = { width: \"var(--control-icon)\", height: \"var(--control-icon)\" };\n\nconst variants = {\n primary: { background: \"var(--action-primary)\", color: \"var(--on-accent)\" },\n dark: { background: \"var(--action-dark)\", color: \"var(--action-dark-fg)\" },\n outline: { background: \"var(--bg-surface)\", color: \"var(--text-body)\", borderColor: \"var(--border-control)\" },\n ghost: { color: \"var(--text-body)\" },\n \"primary-soft\": { background: \"var(--soft-bg)\", color: \"var(--action-primary)\", borderColor: \"var(--soft-border)\" },\n danger: { background: \"var(--danger)\", color: \"var(--on-accent)\" },\n \"danger-soft\": { background: \"var(--danger-bg)\", color: \"var(--danger-text)\" },\n text: { color: \"var(--text-secondary)\", padding: \"0\", height: \"auto\" },\n};\nconst hovers = {\n primary: \"var(--action-primary-hover)\", dark: \"var(--action-dark-hover)\",\n outline: \"var(--bg-hover)\", ghost: \"var(--bg-hover)\", \"primary-soft\": \"var(--soft-hover)\",\n danger: \"var(--danger-text)\", \"danger-soft\": \"var(--danger-soft-hover)\",\n};\n/** Press (mouse-down) fills — one step past hover. */\nconst presses = {\n primary: \"var(--action-primary-active)\", dark: \"var(--action-dark-active)\",\n outline: \"var(--bg-press)\", ghost: \"var(--bg-press)\", \"primary-soft\": \"var(--soft-active)\",\n danger: \"var(--danger-active)\", \"danger-soft\": \"var(--danger-soft-active)\",\n};\n/** Variants that change text color (+ underline) on hover instead of a background wash. */\nconst colorHoverVariants = { text: \"var(--text-heading)\" };\n\nfunction Spinner({ size, color }) {\n return <span style={{ display: \"inline-block\", width: size, height: size, ...(size ? null : tierIcon), borderRadius: \"var(--radius-full)\", border: \"2px solid currentColor\", borderTopColor: \"transparent\", opacity: .9, color, animation: \"kb-spin .7s linear infinite\", flexShrink: 0 }} />;\n}\n\n/** Keybricks button. variant: primary | dark | outline | ghost | primary-soft | danger | danger-soft | text; size: sm 24 | md 32 | lg 36 — omit it to inherit the region's tier (the default). Interaction states: hover (one step darker) · press (two steps, set via mouse-down) · keyboard focus ring · loading · disabled. */\nexport function Button({ variant = \"primary\", size, icon, iconSize, iconPosition = \"left\", medium, disabled, loading, fullWidth, iconOnly, label, pressed, focused, children, style, onClick, ...rest }) {\n const [hover, setHover] = React.useState(false);\n const [press, setPress] = React.useState(false);\n const [focus, setFocus] = React.useState(false);\n const busy = disabled || loading;\n const isPressed = press || pressed;\n const isFocused = focus || focused;\n const s = {\n ...btnBase, ...variants[variant],\n ...(medium ? { fontWeight: \"var(--weight-medium)\" } : null),\n ...(fullWidth ? { width: \"100%\" } : null),\n ...(iconOnly ? { width: \"var(--control-h)\", padding: 0, gap: 0 } : null),\n ...(busy ? { opacity: .55, cursor: \"default\" } : null),\n ...style,\n };\n if (!busy) {\n if (colorHoverVariants[variant]) {\n if (hover || isPressed) { s.color = colorHoverVariants[variant]; s.textDecoration = \"underline\"; }\n if (isPressed) s.opacity = .7;\n } else if (isPressed) {\n s.background = presses[variant];\n } else if (hover) {\n s.background = hovers[variant];\n }\n if (isFocused) s.boxShadow = \"var(--ring-focus)\";\n }\n const iconStyle = iconSize ? null : tierIcon;\n const leading = loading ? <Spinner size={iconSize} color={s.color} /> : (icon && iconPosition === \"left\" ? <Icon name={icon} size={iconSize || 16} style={iconStyle} /> : null);\n const trailing = !loading && icon && iconPosition === \"right\" ? <Icon name={icon} size={iconSize || 16} style={iconStyle} /> : null;\n return (\n <button type=\"button\" data-press=\"own\" data-size={size} style={s} disabled={busy} aria-label={iconOnly ? label : undefined} onClick={onClick}\n onMouseEnter={() => setHover(true)} onMouseLeave={() => { setHover(false); setPress(false); }}\n onMouseDown={() => setPress(true)} onMouseUp={() => setPress(false)}\n onKeyDown={(e) => { if (e.key === \" \" || e.key === \"Enter\") setPress(true); }} onKeyUp={() => setPress(false)}\n onFocus={(e) => { try { setFocus(e.target.matches(\":focus-visible\")); } catch (err) { setFocus(true); } }} onBlur={() => setFocus(false)} {...rest}>\n {leading}\n {iconOnly ? null : children}\n {trailing}\n </button>\n );\n}\n\n/** Attached row of Buttons sharing one outline (segmented action group). Children should be <Button variant=\"outline\"> or similar. */\nexport function ButtonGroup({ children, style }) {\n const items = React.Children.toArray(children);\n return (\n <div style={{ display: \"inline-flex\", ...style }}>\n {items.map((child, i) => React.cloneElement(child, {\n key: i,\n style: {\n ...(child.props.style || {}),\n borderRadius: 0,\n ...(i === 0 ? { borderTopLeftRadius: \"var(--radius-md)\", borderBottomLeftRadius: \"var(--radius-md)\" } : null),\n ...(i === items.length - 1 ? { borderTopRightRadius: \"var(--radius-md)\", borderBottomRightRadius: \"var(--radius-md)\" } : null),\n marginLeft: i === 0 ? 0 : -1,\n },\n }))}\n </div>\n );\n}\n","buttons/Button.vue":"<script setup>\nimport { px } from '../px.js'\nimport { computed, ref } from 'vue'\nimport Icon from '../icons/Icon.vue'\n\n// Every dimension comes from the size tier the button sits in (tokens/layout.css): height, text, icon and padding\n// switch together when a region declares data-size=\"sm\" | \"md\" | \"lg\". The `size` prop only stamps that attribute on\n// the button itself — the default is to inherit, so siblings in one bar can never disagree.\nconst btnBase = { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: '6px', height: 'var(--control-h)', padding: '0 var(--control-px)', borderRadius: 'var(--radius-md)', fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-regular)', fontSize: 'var(--control-text)', lineHeight: 'var(--control-leading)', letterSpacing: 'var(--control-tracking)', border: '1px solid transparent', cursor: 'pointer', whiteSpace: 'nowrap', boxSizing: 'border-box', background: 'transparent', transition: 'var(--t-hover)' }\nconst tierIcon = { width: 'var(--control-icon)', height: 'var(--control-icon)' }\nconst variants = {\n primary: { background: 'var(--action-primary)', color: 'var(--on-accent)' },\n dark: { background: 'var(--action-dark)', color: 'var(--action-dark-fg)' },\n outline: { background: 'var(--bg-surface)', color: 'var(--text-body)', borderColor: 'var(--border-control)' },\n ghost: { color: 'var(--text-body)' },\n 'primary-soft': { background: 'var(--soft-bg)', color: 'var(--action-primary)', borderColor: 'var(--soft-border)' },\n danger: { background: 'var(--danger)', color: 'var(--on-accent)' },\n 'danger-soft': { background: 'var(--danger-bg)', color: 'var(--danger-text)' },\n text: { color: 'var(--text-secondary)', padding: '0', height: 'auto' },\n}\nconst hovers = { primary: 'var(--action-primary-hover)', dark: 'var(--action-dark-hover)', outline: 'var(--bg-hover)', ghost: 'var(--bg-hover)', 'primary-soft': 'var(--soft-hover)', danger: 'var(--danger-text)', 'danger-soft': 'var(--danger-soft-hover)' }\nconst presses = { primary: 'var(--action-primary-active)', dark: 'var(--action-dark-active)', outline: 'var(--bg-press)', ghost: 'var(--bg-press)', 'primary-soft': 'var(--soft-active)', danger: 'var(--danger-active)', 'danger-soft': 'var(--danger-soft-active)' }\nconst colorHoverVariants = { text: 'var(--text-heading)' }\n\n// Button — variant: primary | dark | outline | ghost | primary-soft | danger | danger-soft | text; size: sm 24 | md 32 | lg 36 — omit it to inherit the region's tier (the default).\nconst props = defineProps({\n variant: { type: String, default: 'primary' }, size: String,\n icon: String, iconSize: Number, iconPosition: { type: String, default: 'left' },\n medium: Boolean, disabled: Boolean, loading: Boolean, fullWidth: Boolean, iconOnly: Boolean,\n label: String, pressed: Boolean, focused: Boolean, style: Object,\n})\ndefineEmits(['click'])\nconst hover = ref(false), press = ref(false), focus = ref(false)\nconst busy = computed(() => props.disabled || props.loading)\nconst isPressed = computed(() => press.value || props.pressed)\nconst isFocused = computed(() => focus.value || props.focused)\nconst s = computed(() => {\n const base = { ...btnBase, ...variants[props.variant],\n ...(props.medium ? { fontWeight: 'var(--weight-medium)' } : null),\n ...(props.fullWidth ? { width: '100%' } : null),\n ...(props.iconOnly ? { width: 'var(--control-h)', padding: 0, gap: 0 } : null),\n ...(busy.value ? { opacity: .55, cursor: 'default' } : null), ...props.style }\n if (!busy.value) {\n if (colorHoverVariants[props.variant]) {\n if (hover.value || isPressed.value) { base.color = colorHoverVariants[props.variant]; base.textDecoration = 'underline' }\n if (isPressed.value) base.opacity = .7\n } else if (isPressed.value) base.background = presses[props.variant]\n else if (hover.value) base.background = hovers[props.variant]\n if (isFocused.value) base.boxShadow = 'var(--ring-focus)'\n }\n return base\n})\nconst iSize = computed(() => props.iconSize || 16)\nconst iconStyle = computed(() => props.iconSize ? null : tierIcon)\n</script>\n<template>\n <button type=\"button\" data-press=\"own\" :data-size=\"size\" :style=\"s\" :disabled=\"busy\" :aria-label=\"iconOnly ? label : undefined\"\n @click=\"$emit('click')\" @mouseenter=\"hover = true\" @mouseleave=\"hover = false; press = false\"\n @mousedown=\"press = true\" @mouseup=\"press = false\" @keydown.enter=\"press = true\" @keydown.space=\"press = true\" @keyup=\"press = false\"\n @focus=\"focus = $event.target.matches(':focus-visible')\" @blur=\"focus = false\">\n <span v-if=\"loading\" :style=\"{ display: 'inline-block', width: px(iSize), height: px(iSize), ...iconStyle, borderRadius: 'var(--radius-full)', border: '2px solid currentColor', borderTopColor: 'transparent', opacity: .9, animation: 'kb-spin .7s linear infinite', flexShrink: 0 }\" />\n <Icon v-else-if=\"icon && iconPosition === 'left'\" :name=\"icon\" :size=\"iSize\" :style=\"iconStyle\" />\n <slot v-if=\"!iconOnly\" />\n <Icon v-if=\"!loading && icon && iconPosition === 'right'\" :name=\"icon\" :size=\"iSize\" :style=\"iconStyle\" />\n </button>\n</template>\n","buttons/IconButton.jsx":"import React from \"react\";\nimport { Icon } from \"../icons/Icon.jsx\";\n\n/* A square of the region's control height, icon at the tier's icon size (tokens/layout.css). `size` stamps\n data-size on the button; omit it to inherit — the default. \"xs\" is kept as an alias of \"sm\" for 1.x callers. */\nconst tierIcon = { width: \"var(--control-icon)\", height: \"var(--control-icon)\" };\n\n/** Square ghost icon button (toolbar/back/bell/view toggles). size: sm 24 | md 32 | lg 36 — omit to inherit the region's tier. danger tints red; loading shows a spinner and disables interaction. States: hover · press · keyboard focus ring · active (persistent toggle-on) · disabled. */\nexport function IconButton({ icon, size, active, muted, danger, disabled, loading, label, pressed, focused, style, onClick, ...rest }) {\n const [hover, setHover] = React.useState(false);\n const [press, setPress] = React.useState(false);\n const [focus, setFocus] = React.useState(false);\n const tier = size === \"xs\" ? \"sm\" : size;\n const busy = disabled || loading;\n const isPressed = (press || pressed) && !busy;\n const color = danger ? \"var(--danger)\" : muted ? \"var(--text-muted)\" : \"var(--text-body)\";\n const bg = isPressed ? (danger ? \"var(--danger-soft-active)\" : \"var(--bg-press)\")\n : active ? \"var(--bg-active)\"\n : hover && !busy ? (danger ? \"var(--danger-bg)\" : \"var(--bg-hover)\") : \"transparent\";\n return (\n <button type=\"button\" data-press=\"own\" data-size={tier} aria-label={label} disabled={busy} onClick={onClick}\n onMouseEnter={() => setHover(true)} onMouseLeave={() => { setHover(false); setPress(false); }}\n onMouseDown={() => setPress(true)} onMouseUp={() => setPress(false)}\n onKeyDown={(e) => { if (e.key === \" \" || e.key === \"Enter\") setPress(true); }} onKeyUp={() => setPress(false)}\n onFocus={(e) => { try { setFocus(e.target.matches(\":focus-visible\")); } catch (err) { setFocus(true); } }} onBlur={() => setFocus(false)}\n style={{ width: \"var(--control-h)\", height: \"var(--control-h)\", borderRadius: \"var(--radius-md)\", border: \"none\", cursor: busy ? \"default\" : \"pointer\", display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\", background: bg, color, opacity: busy ? .5 : 1, boxShadow: (focus || focused) && !busy ? \"var(--ring-focus)\" : \"none\", transition: \"var(--t-hover)\", padding: 0, flexShrink: 0, ...style }} {...rest}>\n {loading ? <span style={{ display: \"inline-block\", ...tierIcon, borderRadius: \"var(--radius-full)\", border: \"2px solid currentColor\", borderTopColor: \"transparent\", animation: \"kb-spin .7s linear infinite\" }} /> : <Icon name={icon} size={16} style={tierIcon} />}\n </button>\n );\n}\n","buttons/IconButton.vue":"<script setup>\nimport { ref, computed } from 'vue'\nimport Icon from '../icons/Icon.vue'\n// A square of the region's control height, icon at the tier's icon size (tokens/layout.css). `size` stamps data-size on\n// the button; omit it to inherit — the default. \"xs\" is kept as an alias of \"sm\" for 1.x callers.\nconst tierIcon = { width: 'var(--control-icon)', height: 'var(--control-icon)' }\n// Square ghost icon button (toolbar/back/bell/view toggles). size: sm 24 | md 32 | lg 36 — omit to inherit the region's tier.\nconst props = defineProps({ icon: String, size: String, active: Boolean, muted: Boolean, danger: Boolean, disabled: Boolean, loading: Boolean, label: String, pressed: Boolean, focused: Boolean, style: Object })\ndefineEmits(['click'])\nconst hover = ref(false), press = ref(false), focus = ref(false)\nconst tier = computed(() => props.size === 'xs' ? 'sm' : props.size)\nconst busy = computed(() => props.disabled || props.loading)\nconst isPressed = computed(() => (press.value || props.pressed) && !busy.value)\nconst color = computed(() => props.danger ? 'var(--danger)' : props.muted ? 'var(--text-muted)' : 'var(--text-body)')\nconst bg = computed(() => isPressed.value ? (props.danger ? 'var(--danger-soft-active)' : 'var(--bg-press)') : props.active ? 'var(--bg-active)' : (hover.value && !busy.value ? (props.danger ? 'var(--danger-bg)' : 'var(--bg-hover)') : 'transparent'))\nconst s = computed(() => ({ width: 'var(--control-h)', height: 'var(--control-h)', borderRadius: 'var(--radius-md)', border: 'none', cursor: busy.value ? 'default' : 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', background: bg.value, color: color.value, opacity: busy.value ? .5 : 1, boxShadow: (focus.value || props.focused) && !busy.value ? 'var(--ring-focus)' : 'none', transition: 'var(--t-hover)', padding: 0, flexShrink: 0, ...props.style }))\n</script>\n<template>\n <button type=\"button\" data-press=\"own\" :data-size=\"tier\" :aria-label=\"label\" :disabled=\"busy\" @click=\"$emit('click')\" @mouseenter=\"hover = true\" @mouseleave=\"hover = false; press = false\" @mousedown=\"press = true\" @mouseup=\"press = false\" @keydown.enter=\"press = true\" @keydown.space=\"press = true\" @keyup=\"press = false\" @focus=\"focus = $event.target.matches(':focus-visible')\" @blur=\"focus = false\" :style=\"s\">\n <span v-if=\"loading\" :style=\"{ display: 'inline-block', ...tierIcon, borderRadius: 'var(--radius-full)', border: '2px solid currentColor', borderTopColor: 'transparent', animation: 'kb-spin .7s linear infinite' }\" />\n <Icon v-else :name=\"icon\" :size=\"16\" :style=\"tierIcon\" />\n </button>\n</template>\n","buttons/ButtonGroup.vue":"<script setup>\nimport { useSlots, computed } from 'vue'\nconst props = defineProps({ style: Object })\nconst slots = useSlots()\nconst items = computed(() => slots.default ? slots.default() : [])\n</script>\n<template>\n <div :style=\"{ display: 'inline-flex', ...style }\">\n <template v-for=\"(child, i) in items\" :key=\"i\">\n <component :is=\"child\" :style=\"{ borderRadius: 0,\n ...(i === 0 ? { borderTopLeftRadius: 'var(--radius-md)', borderBottomLeftRadius: 'var(--radius-md)' } : null),\n ...(i === items.length - 1 ? { borderTopRightRadius: 'var(--radius-md)', borderBottomRightRadius: 'var(--radius-md)' } : null),\n marginLeft: i === 0 ? 0 : '-1px' }\" />\n </template>\n </div>\n</template>\n"});
|
|
1
|
+
window.__KB_SRC__=Object.assign(window.__KB_SRC__||{},{"buttons/ActionChip.jsx":"import React from \"react\";\n\nconst chipTones = {\n success: { background: \"var(--success-bg)\", color: \"var(--success-text)\" },\n warning: { background: \"var(--warning-bg)\", color: \"var(--warning-text)\" },\n neutral: { background: \"var(--bg-hover)\", color: \"var(--text-body)\" },\n info: { background: \"var(--info-bg)\", color: \"var(--action-primary)\" },\n danger: { background: \"var(--danger-bg)\", color: \"var(--danger-text)\" },\n};\n\n/** Tinted bulk-action chip (\"Mark as New\", \"Mark as Overwrite\", \"Skip Selected\"). A control: it takes the region's tier height and text; `size` overrides it. */\nexport function ActionChip({ tone = \"neutral\", size, children, onClick, style }) {\n const [hover, setHover] = React.useState(false);\n return (\n <button type=\"button\" data-size={size} onClick={onClick} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}\n style={{ height: \"var(--control-h)\", padding: \"0 var(--control-px)\", borderRadius: \"var(--radius-md)\", border: \"none\", cursor: \"pointer\", fontFamily: \"var(--font-sans)\", fontWeight: \"var(--weight-medium)\", fontSize: \"var(--control-text)\", lineHeight: \"var(--control-leading)\", letterSpacing: \"var(--control-tracking)\", display: \"inline-flex\", alignItems: \"center\", filter: hover ? \"brightness(1.06) saturate(1.05)\" : \"none\", transition: \"var(--t-hover),filter var(--dur-fast) var(--ease-out)\", ...chipTones[tone], ...style }}>\n {children}\n </button>\n );\n}\n","buttons/ActionChip.vue":"<script setup>\nimport { ref, computed } from 'vue'\nconst chipTones = {\n success: { background: 'var(--success-bg)', color: 'var(--success-text)' },\n warning: { background: 'var(--warning-bg)', color: 'var(--warning-text)' },\n neutral: { background: 'var(--bg-hover)', color: 'var(--text-body)' },\n info: { background: 'var(--info-bg)', color: 'var(--action-primary)' },\n danger: { background: 'var(--danger-bg)', color: 'var(--danger-text)' },\n}\n// Tinted bulk-action chip (\"Mark as New\", \"Mark as Overwrite\", \"Skip Selected\"). A control: it takes the region's tier height and text; `size` overrides it.\nconst props = defineProps({ tone: { type: String, default: 'neutral' }, size: String, style: Object })\ndefineEmits(['click'])\nconst hover = ref(false)\nconst s = computed(() => ({ height: 'var(--control-h)', padding: '0 var(--control-px)', borderRadius: 'var(--radius-md)', border: 'none', cursor: 'pointer', fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-medium)', fontSize: 'var(--control-text)', lineHeight: 'var(--control-leading)', letterSpacing: 'var(--control-tracking)', display: 'inline-flex', alignItems: 'center', filter: hover.value ? 'brightness(1.06) saturate(1.05)' : 'none', transition: 'var(--t-hover),filter var(--dur-fast) var(--ease-out)', ...chipTones[props.tone], ...props.style }))\n</script>\n<template>\n <button type=\"button\" :data-size=\"size\" @click=\"$emit('click')\" @mouseenter=\"hover = true\" @mouseleave=\"hover = false\" :style=\"s\"><slot /></button>\n</template>\n","buttons/Button.jsx":"import React from \"react\";\nimport { Icon } from \"../icons/Icon.jsx\";\n\n/* Every dimension comes from the size tier the button sits in (tokens/layout.css): height, text, icon and padding\n switch together when a region declares data-size=\"sm\" | \"md\" | \"lg\". A `size` prop only stamps that attribute on\n the button itself — the default is to inherit, so siblings in one bar can never disagree. */\nconst btnBase = { display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\", gap: 6, height: \"var(--control-h)\", padding: \"0 var(--control-px)\", borderRadius: \"var(--radius-md)\", fontFamily: \"var(--font-sans)\", fontWeight: \"var(--weight-regular)\", fontSize: \"var(--control-text)\", lineHeight: \"var(--control-leading)\", letterSpacing: \"var(--control-tracking)\", border: \"1px solid transparent\", cursor: \"pointer\", whiteSpace: \"nowrap\", boxSizing: \"border-box\", background: \"transparent\", transition: \"var(--t-hover)\" };\nconst tierIcon = { width: \"var(--control-icon)\", height: \"var(--control-icon)\" };\n\nconst variants = {\n primary: { background: \"var(--action-primary)\", color: \"var(--on-accent)\" },\n dark: { background: \"var(--action-dark)\", color: \"var(--action-dark-fg)\" },\n outline: { background: \"var(--bg-surface)\", color: \"var(--text-body)\", borderColor: \"var(--border-control)\" },\n ghost: { color: \"var(--text-body)\" },\n \"primary-soft\": { background: \"var(--soft-bg)\", color: \"var(--action-primary)\", borderColor: \"var(--soft-border)\" },\n danger: { background: \"var(--danger)\", color: \"var(--on-accent)\" },\n \"danger-soft\": { background: \"var(--danger-bg)\", color: \"var(--danger-text)\" },\n text: { color: \"var(--text-secondary)\", padding: \"0\", height: \"auto\" },\n};\nconst hovers = {\n primary: \"var(--action-primary-hover)\", dark: \"var(--action-dark-hover)\",\n outline: \"var(--bg-hover)\", ghost: \"var(--bg-hover)\", \"primary-soft\": \"var(--soft-hover)\",\n danger: \"var(--danger-text)\", \"danger-soft\": \"var(--danger-soft-hover)\",\n};\n/** Press (mouse-down) fills — one step past hover. */\nconst presses = {\n primary: \"var(--action-primary-active)\", dark: \"var(--action-dark-active)\",\n outline: \"var(--bg-press)\", ghost: \"var(--bg-press)\", \"primary-soft\": \"var(--soft-active)\",\n danger: \"var(--danger-active)\", \"danger-soft\": \"var(--danger-soft-active)\",\n};\n/** Variants that change text color (+ underline) on hover instead of a background wash. */\nconst colorHoverVariants = { text: \"var(--text-heading)\" };\n\nfunction Spinner({ size, color }) {\n return <span style={{ display: \"inline-block\", width: size, height: size, ...(size ? null : tierIcon), borderRadius: \"var(--radius-full)\", border: \"2px solid currentColor\", borderTopColor: \"transparent\", opacity: .9, color, animation: \"kb-spin .7s linear infinite\", flexShrink: 0 }} />;\n}\n\n/** Keybricks button. variant: primary | dark | outline | ghost | primary-soft | danger | danger-soft | text; size: sm 28 | md 32 | lg 40 — omit it to inherit the region's tier (the default). Interaction states: hover (one step darker) · press (two steps, set via mouse-down) · keyboard focus ring · loading · disabled. */\nexport function Button({ variant = \"primary\", size, icon, iconSize, iconPosition = \"left\", medium, disabled, loading, fullWidth, iconOnly, label, pressed, focused, children, style, onClick, ...rest }) {\n const [hover, setHover] = React.useState(false);\n const [press, setPress] = React.useState(false);\n const [focus, setFocus] = React.useState(false);\n const busy = disabled || loading;\n const isPressed = press || pressed;\n const isFocused = focus || focused;\n const s = {\n ...btnBase, ...variants[variant],\n ...(medium ? { fontWeight: \"var(--weight-medium)\" } : null),\n ...(fullWidth ? { width: \"100%\" } : null),\n ...(iconOnly ? { width: \"var(--control-h)\", padding: 0, gap: 0 } : null),\n ...(busy ? { opacity: .55, cursor: \"default\" } : null),\n ...style,\n };\n if (!busy) {\n if (colorHoverVariants[variant]) {\n if (hover || isPressed) { s.color = colorHoverVariants[variant]; s.textDecoration = \"underline\"; }\n if (isPressed) s.opacity = .7;\n } else if (isPressed) {\n s.background = presses[variant];\n } else if (hover) {\n s.background = hovers[variant];\n }\n if (isFocused) s.boxShadow = \"var(--ring-focus)\";\n }\n const iconStyle = iconSize ? null : tierIcon;\n const leading = loading ? <Spinner size={iconSize} color={s.color} /> : (icon && iconPosition === \"left\" ? <Icon name={icon} size={iconSize || 16} style={iconStyle} /> : null);\n const trailing = !loading && icon && iconPosition === \"right\" ? <Icon name={icon} size={iconSize || 16} style={iconStyle} /> : null;\n return (\n <button type=\"button\" data-press=\"own\" data-size={size} style={s} disabled={busy} aria-label={iconOnly ? label : undefined} onClick={onClick}\n onMouseEnter={() => setHover(true)} onMouseLeave={() => { setHover(false); setPress(false); }}\n onMouseDown={() => setPress(true)} onMouseUp={() => setPress(false)}\n onKeyDown={(e) => { if (e.key === \" \" || e.key === \"Enter\") setPress(true); }} onKeyUp={() => setPress(false)}\n onFocus={(e) => { try { setFocus(e.target.matches(\":focus-visible\")); } catch (err) { setFocus(true); } }} onBlur={() => setFocus(false)} {...rest}>\n {leading}\n {iconOnly ? null : children}\n {trailing}\n </button>\n );\n}\n\n/** Attached row of Buttons sharing one outline (segmented action group). Children should be <Button variant=\"outline\"> or similar. */\nexport function ButtonGroup({ children, style }) {\n const items = React.Children.toArray(children);\n return (\n <div style={{ display: \"inline-flex\", ...style }}>\n {items.map((child, i) => React.cloneElement(child, {\n key: i,\n style: {\n ...(child.props.style || {}),\n borderRadius: 0,\n ...(i === 0 ? { borderTopLeftRadius: \"var(--radius-md)\", borderBottomLeftRadius: \"var(--radius-md)\" } : null),\n ...(i === items.length - 1 ? { borderTopRightRadius: \"var(--radius-md)\", borderBottomRightRadius: \"var(--radius-md)\" } : null),\n marginLeft: i === 0 ? 0 : -1,\n },\n }))}\n </div>\n );\n}\n","buttons/Button.vue":"<script setup>\nimport { px } from '../px.js'\nimport { computed, ref } from 'vue'\nimport Icon from '../icons/Icon.vue'\n\n// Every dimension comes from the size tier the button sits in (tokens/layout.css): height, text, icon and padding\n// switch together when a region declares data-size=\"sm\" | \"md\" | \"lg\". The `size` prop only stamps that attribute on\n// the button itself — the default is to inherit, so siblings in one bar can never disagree.\nconst btnBase = { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: '6px', height: 'var(--control-h)', padding: '0 var(--control-px)', borderRadius: 'var(--radius-md)', fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-regular)', fontSize: 'var(--control-text)', lineHeight: 'var(--control-leading)', letterSpacing: 'var(--control-tracking)', border: '1px solid transparent', cursor: 'pointer', whiteSpace: 'nowrap', boxSizing: 'border-box', background: 'transparent', transition: 'var(--t-hover)' }\nconst tierIcon = { width: 'var(--control-icon)', height: 'var(--control-icon)' }\nconst variants = {\n primary: { background: 'var(--action-primary)', color: 'var(--on-accent)' },\n dark: { background: 'var(--action-dark)', color: 'var(--action-dark-fg)' },\n outline: { background: 'var(--bg-surface)', color: 'var(--text-body)', borderColor: 'var(--border-control)' },\n ghost: { color: 'var(--text-body)' },\n 'primary-soft': { background: 'var(--soft-bg)', color: 'var(--action-primary)', borderColor: 'var(--soft-border)' },\n danger: { background: 'var(--danger)', color: 'var(--on-accent)' },\n 'danger-soft': { background: 'var(--danger-bg)', color: 'var(--danger-text)' },\n text: { color: 'var(--text-secondary)', padding: '0', height: 'auto' },\n}\nconst hovers = { primary: 'var(--action-primary-hover)', dark: 'var(--action-dark-hover)', outline: 'var(--bg-hover)', ghost: 'var(--bg-hover)', 'primary-soft': 'var(--soft-hover)', danger: 'var(--danger-text)', 'danger-soft': 'var(--danger-soft-hover)' }\nconst presses = { primary: 'var(--action-primary-active)', dark: 'var(--action-dark-active)', outline: 'var(--bg-press)', ghost: 'var(--bg-press)', 'primary-soft': 'var(--soft-active)', danger: 'var(--danger-active)', 'danger-soft': 'var(--danger-soft-active)' }\nconst colorHoverVariants = { text: 'var(--text-heading)' }\n\n// Button — variant: primary | dark | outline | ghost | primary-soft | danger | danger-soft | text; size: sm 28 | md 32 | lg 40 — omit it to inherit the region's tier (the default).\nconst props = defineProps({\n variant: { type: String, default: 'primary' }, size: String,\n icon: String, iconSize: Number, iconPosition: { type: String, default: 'left' },\n medium: Boolean, disabled: Boolean, loading: Boolean, fullWidth: Boolean, iconOnly: Boolean,\n label: String, pressed: Boolean, focused: Boolean, style: Object,\n})\ndefineEmits(['click'])\nconst hover = ref(false), press = ref(false), focus = ref(false)\nconst busy = computed(() => props.disabled || props.loading)\nconst isPressed = computed(() => press.value || props.pressed)\nconst isFocused = computed(() => focus.value || props.focused)\nconst s = computed(() => {\n const base = { ...btnBase, ...variants[props.variant],\n ...(props.medium ? { fontWeight: 'var(--weight-medium)' } : null),\n ...(props.fullWidth ? { width: '100%' } : null),\n ...(props.iconOnly ? { width: 'var(--control-h)', padding: 0, gap: 0 } : null),\n ...(busy.value ? { opacity: .55, cursor: 'default' } : null), ...props.style }\n if (!busy.value) {\n if (colorHoverVariants[props.variant]) {\n if (hover.value || isPressed.value) { base.color = colorHoverVariants[props.variant]; base.textDecoration = 'underline' }\n if (isPressed.value) base.opacity = .7\n } else if (isPressed.value) base.background = presses[props.variant]\n else if (hover.value) base.background = hovers[props.variant]\n if (isFocused.value) base.boxShadow = 'var(--ring-focus)'\n }\n return base\n})\nconst iSize = computed(() => props.iconSize || 16)\nconst iconStyle = computed(() => props.iconSize ? null : tierIcon)\n</script>\n<template>\n <button type=\"button\" data-press=\"own\" :data-size=\"size\" :style=\"s\" :disabled=\"busy\" :aria-label=\"iconOnly ? label : undefined\"\n @click=\"$emit('click')\" @mouseenter=\"hover = true\" @mouseleave=\"hover = false; press = false\"\n @mousedown=\"press = true\" @mouseup=\"press = false\" @keydown.enter=\"press = true\" @keydown.space=\"press = true\" @keyup=\"press = false\"\n @focus=\"focus = $event.target.matches(':focus-visible')\" @blur=\"focus = false\">\n <span v-if=\"loading\" :style=\"{ display: 'inline-block', width: px(iSize), height: px(iSize), ...iconStyle, borderRadius: 'var(--radius-full)', border: '2px solid currentColor', borderTopColor: 'transparent', opacity: .9, animation: 'kb-spin .7s linear infinite', flexShrink: 0 }\" />\n <Icon v-else-if=\"icon && iconPosition === 'left'\" :name=\"icon\" :size=\"iSize\" :style=\"iconStyle\" />\n <slot v-if=\"!iconOnly\" />\n <Icon v-if=\"!loading && icon && iconPosition === 'right'\" :name=\"icon\" :size=\"iSize\" :style=\"iconStyle\" />\n </button>\n</template>\n","buttons/IconButton.jsx":"import React from \"react\";\nimport { Icon } from \"../icons/Icon.jsx\";\n\n/* A square of the region's control height, icon at the tier's icon size (tokens/layout.css). `size` stamps\n data-size on the button; omit it to inherit — the default. \"xs\" is kept as an alias of \"sm\" for 1.x callers. */\nconst tierIcon = { width: \"var(--control-icon)\", height: \"var(--control-icon)\" };\n\n/** Square ghost icon button (toolbar/back/bell/view toggles). size: sm 28 | md 32 | lg 40 — omit to inherit the region's tier. danger tints red; loading shows a spinner and disables interaction. States: hover · press · keyboard focus ring · active (persistent toggle-on) · disabled. */\nexport function IconButton({ icon, size, active, muted, danger, disabled, loading, label, pressed, focused, style, onClick, ...rest }) {\n const [hover, setHover] = React.useState(false);\n const [press, setPress] = React.useState(false);\n const [focus, setFocus] = React.useState(false);\n const tier = size === \"xs\" ? \"sm\" : size;\n const busy = disabled || loading;\n const isPressed = (press || pressed) && !busy;\n const color = danger ? \"var(--danger)\" : muted ? \"var(--text-muted)\" : \"var(--text-body)\";\n // hover / press are alpha overlays, not solid steps: the button sits on white rows, grey table headers and grey bars alike,\n // and an overlay darkens whatever is underneath by the same amount (a solid --bg-hover vanishes on a --bg-table-header).\n const bg = isPressed ? (danger ? \"var(--danger-soft-active)\" : \"var(--overlay-press)\")\n : active ? \"var(--bg-active)\"\n : hover && !busy ? (danger ? \"var(--danger-bg)\" : \"var(--overlay-hover)\") : \"transparent\";\n return (\n <button type=\"button\" data-press=\"own\" data-size={tier} aria-label={label} disabled={busy} onClick={onClick}\n onMouseEnter={() => setHover(true)} onMouseLeave={() => { setHover(false); setPress(false); }}\n onMouseDown={() => setPress(true)} onMouseUp={() => setPress(false)}\n onKeyDown={(e) => { if (e.key === \" \" || e.key === \"Enter\") setPress(true); }} onKeyUp={() => setPress(false)}\n onFocus={(e) => { try { setFocus(e.target.matches(\":focus-visible\")); } catch (err) { setFocus(true); } }} onBlur={() => setFocus(false)}\n style={{ width: \"var(--control-h)\", height: \"var(--control-h)\", borderRadius: \"var(--radius-md)\", border: \"none\", cursor: busy ? \"default\" : \"pointer\", display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\", background: bg, color, opacity: busy ? .5 : 1, boxShadow: (focus || focused) && !busy ? \"var(--ring-focus)\" : \"none\", transition: \"var(--t-hover)\", padding: 0, flexShrink: 0, ...style }} {...rest}>\n {loading ? <span style={{ display: \"inline-block\", ...tierIcon, borderRadius: \"var(--radius-full)\", border: \"2px solid currentColor\", borderTopColor: \"transparent\", animation: \"kb-spin .7s linear infinite\" }} /> : <Icon name={icon} size={16} style={tierIcon} />}\n </button>\n );\n}\n","buttons/IconButton.vue":"<script setup>\nimport { ref, computed } from 'vue'\nimport Icon from '../icons/Icon.vue'\n// A square of the region's control height, icon at the tier's icon size (tokens/layout.css). `size` stamps data-size on\n// the button; omit it to inherit — the default. \"xs\" is kept as an alias of \"sm\" for 1.x callers.\nconst tierIcon = { width: 'var(--control-icon)', height: 'var(--control-icon)' }\n// Square ghost icon button (toolbar/back/bell/view toggles). size: sm 28 | md 32 | lg 40 — omit to inherit the region's tier.\nconst props = defineProps({ icon: String, size: String, active: Boolean, muted: Boolean, danger: Boolean, disabled: Boolean, loading: Boolean, label: String, pressed: Boolean, focused: Boolean, style: Object })\ndefineEmits(['click'])\nconst hover = ref(false), press = ref(false), focus = ref(false)\nconst tier = computed(() => props.size === 'xs' ? 'sm' : props.size)\nconst busy = computed(() => props.disabled || props.loading)\nconst isPressed = computed(() => (press.value || props.pressed) && !busy.value)\nconst color = computed(() => props.danger ? 'var(--danger)' : props.muted ? 'var(--text-muted)' : 'var(--text-body)')\n// hover / press are alpha overlays so the step is the same on white rows, grey table headers and grey bars\nconst bg = computed(() => isPressed.value ? (props.danger ? 'var(--danger-soft-active)' : 'var(--overlay-press)') : props.active ? 'var(--bg-active)' : (hover.value && !busy.value ? (props.danger ? 'var(--danger-bg)' : 'var(--overlay-hover)') : 'transparent'))\nconst s = computed(() => ({ width: 'var(--control-h)', height: 'var(--control-h)', borderRadius: 'var(--radius-md)', border: 'none', cursor: busy.value ? 'default' : 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', background: bg.value, color: color.value, opacity: busy.value ? .5 : 1, boxShadow: (focus.value || props.focused) && !busy.value ? 'var(--ring-focus)' : 'none', transition: 'var(--t-hover)', padding: 0, flexShrink: 0, ...props.style }))\n</script>\n<template>\n <button type=\"button\" data-press=\"own\" :data-size=\"tier\" :aria-label=\"label\" :disabled=\"busy\" @click=\"$emit('click')\" @mouseenter=\"hover = true\" @mouseleave=\"hover = false; press = false\" @mousedown=\"press = true\" @mouseup=\"press = false\" @keydown.enter=\"press = true\" @keydown.space=\"press = true\" @keyup=\"press = false\" @focus=\"focus = $event.target.matches(':focus-visible')\" @blur=\"focus = false\" :style=\"s\">\n <span v-if=\"loading\" :style=\"{ display: 'inline-block', ...tierIcon, borderRadius: 'var(--radius-full)', border: '2px solid currentColor', borderTopColor: 'transparent', animation: 'kb-spin .7s linear infinite' }\" />\n <Icon v-else :name=\"icon\" :size=\"16\" :style=\"tierIcon\" />\n </button>\n</template>\n","buttons/ButtonGroup.vue":"<script setup>\nimport { useSlots, computed } from 'vue'\nconst props = defineProps({ style: Object })\nconst slots = useSlots()\nconst items = computed(() => slots.default ? slots.default() : [])\n</script>\n<template>\n <div :style=\"{ display: 'inline-flex', ...style }\">\n <template v-for=\"(child, i) in items\" :key=\"i\">\n <component :is=\"child\" :style=\"{ borderRadius: 0,\n ...(i === 0 ? { borderTopLeftRadius: 'var(--radius-md)', borderBottomLeftRadius: 'var(--radius-md)' } : null),\n ...(i === items.length - 1 ? { borderTopRightRadius: 'var(--radius-md)', borderBottomRightRadius: 'var(--radius-md)' } : null),\n marginLeft: i === 0 ? 0 : '-1px' }\" />\n </template>\n </div>\n</template>\n"});
|