@keyfunc/keybricks-ds 1.0.3 → 1.0.4

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 CHANGED
@@ -55,11 +55,11 @@ deploys the documentation site. Watch it under *Build → Pipelines*.
55
55
  **5. Cut the first release.**
56
56
 
57
57
  ```bash
58
- git tag v1.0.0 && git push --tags
58
+ git tag v1.0.4 && git push --tags
59
59
  ```
60
60
 
61
61
  That tag runs `generated:check` → `version:check` → `npm publish`. Confirm under *Deploy →
62
- Package Registry*: `@keyfunc/keybricks-ds` 1.0.0.
62
+ Package Registry*: `@keyfunc/keybricks-ds` 1.0.4.
63
63
 
64
64
  **6. Hand developers two things:** the Pages URL, and the `.npmrc` snippet in §4 below.
65
65
 
@@ -156,7 +156,7 @@ GitLab injects `CI_JOB_TOKEN` — use that instead and no secret is stored anywh
156
156
  **Install — straight from git** (no registry, no publish; works today)
157
157
 
158
158
  ```json
159
- "@keyfunc/keybricks-ds": "git+ssh://git@gitlab.epm2demo.cn/Felix/keybricks-ds.git#v1.0.0"
159
+ "@keyfunc/keybricks-ds": "git+ssh://git@gitlab.epm2demo.cn/Felix/keybricks-ds.git#v1.0.4"
160
160
  ```
161
161
 
162
162
  Because the package has no build step, a git dependency needs no `prepare` script — npm
package/INTEGRATION.md CHANGED
@@ -31,7 +31,7 @@ Not using a registry yet? A git dependency works with no publishing at all — t
31
31
  has no build step, so npm can use the checkout as-is:
32
32
 
33
33
  ```json
34
- "@keyfunc/keybricks-ds": "git+ssh://git@gitlab.epm2demo.cn/Felix/keybricks-ds.git#v1.0.0"
34
+ "@keyfunc/keybricks-ds": "git+ssh://git@gitlab.epm2demo.cn/Felix/keybricks-ds.git#v1.0.4"
35
35
  ```
36
36
 
37
37
  **Source-only package.** `.jsx` and `.vue` files are published as authored, so your
@@ -139,6 +139,7 @@ Shared non-component values live in plain modules: `forms/input-base.js` (`input
139
139
  ```js
140
140
  // React
141
141
  import { Input, Textarea } from '@keyfunc/keybricks-ds/components/forms/Input.jsx'
142
+ import { Radio, RadioGroup } from '@keyfunc/keybricks-ds/components/forms/Radio.jsx' // no longer inside Switch.jsx
142
143
  // Vue
143
144
  import Input from '@keyfunc/keybricks-ds/components/forms/Input.vue'
144
145
  import Textarea from '@keyfunc/keybricks-ds/components/forms/Textarea.vue'
@@ -168,8 +169,8 @@ import Textarea from '@keyfunc/keybricks-ds/components/forms/Textarea.vue'
168
169
  | `MultiSelect` | Checkbox dropdown; picks render as removable tags with `+n` overflow. |
169
170
  | `SearchInput` | Search field with a leading glyph and a clear button. |
170
171
  | `Checkbox` | Two sizes, plus an indeterminate state for parent rows. |
171
- | `Radio` / `RadioGroup` | Single choice from a small set; the group handles layout and keyboard arrows. |
172
- | `Switch` | Immediate on/off toggle (no Save button). Two sizes. |
172
+ | `Radio` / `RadioGroup` | Single choice from 2–5 visible options (past five, use `Select`). `description` adds a muted second line; `row` lays out horizontally; `variant="cards"` renders bordered selectable cards for choices a user must weigh. Arrow keys move the selection. Vue: `v-model`. |
173
+ | `Switch` | Immediate on/off setting (no Save button). Three sizes; `size="lg"` when the knob carries `knobIcon` / `knobText` (one character). `insideOn`/`insideOff` for text in the pill, `labelOn`/`labelOff` for captions beside it (or `label` for a single settings caption). `tone="semantic"` is danger-off → success-on — reserve it for states with real consequence. `beforeChange(next)` returns a promise; the knob spins until it settles. Vue: `v-model:checked`. |
173
174
  | `NumberStepper` | Numeric input with − / + buttons and min/max clamping. |
174
175
  | `Slider` | Range input with a filled track, drag value bubble and optional min/max labels. |
175
176
  | `DatePicker` | Text field plus a month-grid popover. Values are `YYYY-MM-DD` strings. |
@@ -206,7 +207,7 @@ import Textarea from '@keyfunc/keybricks-ds/components/forms/Textarea.vue'
206
207
  | `Tabs` | Page-level underline tabs. |
207
208
  | `PanelTabs` | Compact tabs inside a detail panel or drawer. |
208
209
  | `PillTabs` | Filter/status tabs as pills. |
209
- | `SegmentedControl` | Mutually exclusive options in one control; two sizes, optional icons. |
210
+ | `SegmentedControl` | Switches views of the same data, applies instantly — not a saved form value (`RadioGroup`) and not page navigation (`Tabs`). Two sizes, `icon` per option, `iconOnly`, per-option or whole-control `disabled`, `fullWidth`. ← → keyboard. |
210
211
  | `ViewToggle` | List/grid icon toggle. |
211
212
 
212
213
  ### `feedback/` — status, overlays, progress
@@ -425,7 +426,7 @@ a migration note in the release. Token renames are major because your own code r
425
426
  Pin a minor range and update deliberately:
426
427
 
427
428
  ```json
428
- "@keyfunc/keybricks-ds": "~1.0.0"
429
+ "@keyfunc/keybricks-ds": "~1.0.4"
429
430
  ```
430
431
 
431
432
  Release mechanics, the CI pipeline and the Pages site are documented in `DEPLOY.md`.
@@ -361,6 +361,14 @@
361
361
  "selector": "JSXOpeningElement[name.name='RadarAxis'] > JSXAttribute > JSXIdentifier[name!=/^(?:label|max|key|ref|className|style|children)$/]",
362
362
  "message": "<RadarAxis> doesn't accept that prop. Declared props: label, max."
363
363
  },
364
+ {
365
+ "selector": "JSXOpeningElement[name.name='Radio'] > JSXAttribute > JSXIdentifier[name!=/^(?:checked|onChange|label|description|size|disabled|style|key|ref|className|style|children)$/]",
366
+ "message": "<Radio> doesn't accept that prop. Declared props: checked, onChange, label, description, size, disabled, style."
367
+ },
368
+ {
369
+ "selector": "JSXOpeningElement[name.name='Radio'] > JSXAttribute[name.name='size'] > Literal[value!=/^(?:sm|md)$/]",
370
+ "message": "<Radio> size must be one of 'sm' | 'md'."
371
+ },
364
372
  {
365
373
  "selector": "JSXOpeningElement[name.name='Ribbon3DSeries'] > JSXAttribute > JSXIdentifier[name!=/^(?:name|values|color|key|ref|className|style|children)$/]",
366
374
  "message": "<Ribbon3DSeries> doesn't accept that prop. Declared props: name, values, color."
@@ -382,8 +390,8 @@
382
390
  "message": "<SearchInput> doesn't accept that prop. Declared props: placeholder, bare, value, onChange, disabled, style."
383
391
  },
384
392
  {
385
- "selector": "JSXOpeningElement[name.name='SegmentedControl'] > JSXAttribute > JSXIdentifier[name!=/^(?:options|value|onChange|size|style|key|ref|className|style|children)$/]",
386
- "message": "<SegmentedControl> doesn't accept that prop. Declared props: options, value, onChange, size, style."
393
+ "selector": "JSXOpeningElement[name.name='SegmentedControl'] > JSXAttribute > JSXIdentifier[name!=/^(?:options|value|onChange|size|iconOnly|disabled|fullWidth|style|key|ref|className|style|children)$/]",
394
+ "message": "<SegmentedControl> doesn't accept that prop. Declared props: options, value, onChange, size, iconOnly, disabled, fullWidth, style."
387
395
  },
388
396
  {
389
397
  "selector": "JSXOpeningElement[name.name='SegmentedControl'] > JSXAttribute[name.name='size'] > Literal[value!=/^(?:sm|md)$/]",
@@ -446,12 +454,16 @@
446
454
  "message": "<Surface3D> doesn't accept that prop. Declared props: values, width, height, yaw, pitch, zScale, wire, interactive, valueFormat, style."
447
455
  },
448
456
  {
449
- "selector": "JSXOpeningElement[name.name='Switch'] > JSXAttribute > JSXIdentifier[name!=/^(?:checked|onChange|label|size|disabled|style|key|ref|className|style|children)$/]",
450
- "message": "<Switch> doesn't accept that prop. Declared props: checked, onChange, label, size, disabled, style."
457
+ "selector": "JSXOpeningElement[name.name='Switch'] > JSXAttribute > JSXIdentifier[name!=/^(?:checked|onChange|disabled|size|tone|onColor|offColor|knobIcon|knobText|insideOn|insideOff|inlinePrompt|label|labelOn|labelOff|loading|beforeChange|style|key|ref|className|style|children)$/]",
458
+ "message": "<Switch> doesn't accept that prop. Declared props: checked, onChange, disabled, size, tone, onColor, offColor, knobIcon, knobText, insideOn, insideOff, inlinePrompt, label, labelOn, labelOff, loading, beforeChange, style."
451
459
  },
452
460
  {
453
- "selector": "JSXOpeningElement[name.name='Switch'] > JSXAttribute[name.name='size'] > Literal[value!=/^(?:md|sm)$/]",
454
- "message": "<Switch> size must be one of 'md' | 'sm'."
461
+ "selector": "JSXOpeningElement[name.name='Switch'] > JSXAttribute[name.name='size'] > Literal[value!=/^(?:sm|md|lg)$/]",
462
+ "message": "<Switch> size must be one of 'sm' | 'md' | 'lg'."
463
+ },
464
+ {
465
+ "selector": "JSXOpeningElement[name.name='Switch'] > JSXAttribute[name.name='tone'] > Literal[value!=/^(?:primary|semantic)$/]",
466
+ "message": "<Switch> tone must be one of 'primary' | 'semantic'."
455
467
  },
456
468
  {
457
469
  "selector": "JSXOpeningElement[name.name='Tabs'] > JSXAttribute > JSXIdentifier[name!=/^(?:tabs|active|onChange|style|key|ref|className|style|children)$/]",
@@ -708,6 +720,9 @@
708
720
  "RadarAxis": {
709
721
  "replaces": []
710
722
  },
723
+ "Radio": {
724
+ "replaces": []
725
+ },
711
726
  "Ribbon3DSeries": {
712
727
  "replaces": []
713
728
  },
@@ -0,0 +1,46 @@
1
+ <!-- @dsCard group="Components" viewport="700x620" name="Radio Button" subtitle="Single choice from a small set — md/sm · description · disabled · row · card variant · arrow-key navigation" -->
2
+ <!DOCTYPE html>
3
+ <html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css">
4
+ <script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
5
+ <script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
6
+ <script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
7
+ <script src="../../_ds_bundle.js"></script>
8
+ <script src="../_shared/view-source.js"></script>
9
+ <style>body{margin:0;padding:20px 24px;font-family:var(--font-sans);background:var(--bg-surface)}.sec{font-size:var(--text-2xs);font-weight:600;letter-spacing:.7px;text-transform:uppercase;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:170px 1fr;align-items:start;gap:20px;padding:6px 0}.k{font-size:var(--text-xs);color:var(--text-secondary);font-family:var(--font-mono);padding-top:2px}.v{display:flex;align-items:flex-start;gap:24px;flex-wrap:wrap}.note{font-size:var(--text-xs);line-height:17px;color:var(--text-secondary);max-width:60ch;padding-top:6px}a{color:var(--link)}a:hover{color:var(--link-hover)}</style>
10
+ </head><body><div id="root"></div>
11
+ <script type="text/babel">
12
+ const { Radio, RadioGroup } = window.KeybricksDesignSystem_71231a;
13
+ const Case = ({ k, children }) => <div className="case"><span className="k">{k}</span><div className="v">{children}</div></div>;
14
+ function Sheet() {
15
+ const [a, setA] = React.useState("Overwrite"), [b, setB] = React.useState("Ascending"), [c, setC] = React.useState("weekly"), [d, setD] = React.useState("merge"), [e, setE] = React.useState("USD"), [s1, setS1] = React.useState(true), [s2, setS2] = React.useState(true), [s3, setS3] = React.useState(false);
16
+ return <div>
17
+ <div className="sec">Single radio</div>
18
+ <Case k="md · sm"><Radio checked={s1} onChange={() => setS1(true)} label="Selected" /><Radio checked={!s1} onChange={() => setS1(false)} label="Unselected" /><Radio size="sm" checked={s2} onChange={() => setS2(true)} label="Small" /><Radio size="sm" checked={!s2} onChange={() => setS2(false)} label="Small" /></Case>
19
+ <Case k="disabled"><Radio checked disabled label="Locked on" /><Radio disabled label="Locked off" /></Case>
20
+ <Case k="description"><Radio checked={!s3} onChange={() => setS3(false)} label="Weekly digest" description="One summary every Monday morning" /><Radio checked={s3} onChange={() => setS3(true)} label="Daily" description="Every morning at 08:00" /></Case>
21
+
22
+ <div className="sec">RadioGroup — vertical (default)</div>
23
+ <Case k='options: string[]'><RadioGroup options={["New", "Overwrite", "Skip"]} value={a} onChange={setA} /></Case>
24
+ <Case k="with descriptions"><RadioGroup value={c} onChange={setC} options={[
25
+ { label: "Weekly digest", value: "weekly", description: "One summary every Monday" },
26
+ { label: "Daily", value: "daily", description: "Every morning at 08:00" },
27
+ { label: "Never", value: "never", description: "Only in-app notifications", disabled: true }
28
+ ]} /></Case>
29
+
30
+ <div className="sec">RadioGroup — row · sm</div>
31
+ <Case k="row"><RadioGroup row options={["USD", "EUR", "CNY", "JPY"]} value={e} onChange={setE} /></Case>
32
+ <Case k='row · size="sm"'><RadioGroup row size="sm" options={["Ascending", "Descending"]} value={b} onChange={setB} /></Case>
33
+ <Case k="disabled group"><RadioGroup row disabled options={["Draft", "Published"]} value="Draft" /></Case>
34
+
35
+ <div className="sec">RadioGroup — card variant</div>
36
+ <Case k='variant="cards" row'><RadioGroup variant="cards" row value={d} onChange={setD} style={{ width: 460 }} options={[
37
+ { label: "Merge", value: "merge", description: "Keep target values, add new keys" },
38
+ { label: "Overwrite", value: "overwrite", description: "Target takes source values" },
39
+ { label: "Skip", value: "skip", description: "Leave conflicts untouched", disabled: true }
40
+ ]} /></Case>
41
+ <div className="note">A radio group is the right control for 2–5 mutually exclusive options that should all stay visible. Past five, use <code>Select</code>. Arrow keys move the selection; Space/Enter selects the focused option. Use the card variant when each choice needs a description a user must weigh — migration strategies, plan tiers — never for simple settings.</div>
42
+ </div>;
43
+ }
44
+ ReactDOM.createRoot(document.getElementById("root")).render(<Sheet/>);
45
+ if (window.KBViewSource) setTimeout(function(){ KBViewSource.mount("#root", [{"name":"Radio.jsx","path":"../forms/Radio.jsx"},{"name":"RadioGroup.vue","path":"../forms/RadioGroup.vue","vueOnly":true}]); }, 0);
46
+ </script></body></html>
@@ -0,0 +1,39 @@
1
+ <!-- @dsCard group="Components" viewport="700x520" name="Segmented Control" subtitle="Mutually exclusive views in one inset track — md/sm · icons · icon-only · disabled option · full width · ViewToggle" -->
2
+ <!DOCTYPE html>
3
+ <html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.css">
4
+ <script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
5
+ <script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
6
+ <script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
7
+ <script src="../../_ds_bundle.js"></script>
8
+ <script src="../_shared/view-source.js"></script>
9
+ <style>body{margin:0;padding:20px 24px;font-family:var(--font-sans);background:var(--bg-surface)}.sec{font-size:var(--text-2xs);font-weight:600;letter-spacing:.7px;text-transform:uppercase;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:170px 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-mono)}.v{display:flex;align-items:center;gap:20px;flex-wrap:wrap}.note{font-size:var(--text-xs);line-height:17px;color:var(--text-secondary);max-width:60ch;padding-top:6px}a{color:var(--link)}a:hover{color:var(--link-hover)}</style>
10
+ </head><body><div id="root"></div>
11
+ <script type="text/babel">
12
+ const { SegmentedControl, ViewToggle } = window.KeybricksDesignSystem_71231a;
13
+ const Case = ({ k, children }) => <div className="case"><span className="k">{k}</span><div className="v">{children}</div></div>;
14
+ function Sheet() {
15
+ const [a, setA] = React.useState("Grid"), [b, setB] = React.useState("Last 30 days"), [c, setC] = React.useState("Table"), [d, setD] = React.useState("Actual"), [e, setE] = React.useState("Month"), [f, setF] = React.useState("Overview"), [v, setV] = React.useState("grid");
16
+ return <div>
17
+ <div className="sec">Sizes</div>
18
+ <Case k="md"><SegmentedControl options={["Actual", "Budget", "Variance"]} value={d} onChange={setD} /></Case>
19
+ <Case k="sm"><SegmentedControl size="sm" options={["Last 7 days", "Last 30 days", "Quarter"]} value={b} onChange={setB} /></Case>
20
+
21
+ <div className="sec">With icons</div>
22
+ <Case k="icon + label"><SegmentedControl options={[{ label: "List", icon: "list" }, { label: "Grid", icon: "layout-grid" }]} value={a} onChange={setA} /></Case>
23
+ <Case k="icon only · aria label"><SegmentedControl options={[{ icon: "table", label: "Table" }, { icon: "chart-column", label: "Chart" }, { icon: "code", label: "JSON" }]} iconOnly value={c} onChange={setC} /></Case>
24
+
25
+ <div className="sec">States</div>
26
+ <Case k="disabled option"><SegmentedControl options={[{ label: "Month" }, { label: "Quarter" }, { label: "Year", disabled: true }]} value={e} onChange={setE} /></Case>
27
+ <Case k="disabled control"><SegmentedControl disabled options={["Actual", "Budget"]} value="Actual" /></Case>
28
+
29
+ <div className="sec">Layout</div>
30
+ <Case k="fullWidth"><SegmentedControl fullWidth options={["Overview", "Details", "History"]} value={f} onChange={setF} style={{ width: 400 }} /></Case>
31
+
32
+ <div className="sec">ViewToggle — the two-state shorthand</div>
33
+ <Case k="list / grid"><ViewToggle value={v} onChange={setV} /></Case>
34
+ <div className="note">Segmented control switches <em>views of the same data</em> and applies instantly — never for a form value that gets saved (that's <code>RadioGroup</code>) and never for navigation between pages (that's <code>Tabs</code>). 2–5 options, labels one or two words. <code>ViewToggle</code> is the fixed list/grid pair used in panel headers.</div>
35
+ </div>;
36
+ }
37
+ ReactDOM.createRoot(document.getElementById("root")).render(<Sheet/>);
38
+ if (window.KBViewSource) setTimeout(function(){ KBViewSource.mount("#root", [{"name":"SegmentedControl.jsx","path":"../tabs/SegmentedControl.jsx"},{"name":"ViewToggle.jsx","path":"../tabs/ViewToggle.jsx"}]); }, 0);
39
+ </script></body></html>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Components" viewport="700x260" name="Toggles" subtitle="Switch · Radio · Checkbox · SegmentedControl · ViewToggle — sm/md sizes" -->
1
+ <!-- @dsCard group="Components" viewport="700x1060" name="Toggle Switch" subtitle="Binary settings pill — sizes · semantic red→green · glyph knobs · inline text · captions · async loading" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../_shared/frame-theme.js"></script><link rel="stylesheet" href="../../styles.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>
@@ -6,63 +6,52 @@
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}.lbl{font-size:10px;letter-spacing:.5px;text-transform:uppercase;color:var(--text-muted);display:block;padding-bottom:8px}</style></head>
10
- <body><div id="root"></div>
9
+ <style>body{margin:0;padding:20px 24px;font-family:var(--font-sans);background:var(--bg-surface)}.sec{font-size:var(--text-2xs);font-weight:600;letter-spacing:.7px;text-transform:uppercase;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-mono)}.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)}</style>
10
+ </head><body><div id="root"></div>
11
11
  <script type="text/babel">
12
- const { Switch, Radio, RadioGroup, Checkbox, SegmentedControl, ViewToggle } = window.KeybricksDesignSystem_71231a;
13
- function Sheet(){
14
- const [a,setA]=React.useState(true),[b,setB]=React.useState(false);
15
- const [c1,setC1]=React.useState(true),[c2,setC2]=React.useState(true),[c3,setC3]=React.useState("some");
16
- const [r,setR]=React.useState("Overwrite");
17
- const [s,setS]=React.useState("Grid");
18
- const [t,setT]=React.useState("Last 30 days");
19
- const [v,setV]=React.useState("grid");
12
+ const { Switch } = window.KeybricksDesignSystem_71231a;
13
+ const wait = (ms, ok = true) => new Promise(r => setTimeout(() => r(ok), ms));
14
+ const Case = ({ k, children }) => <div className="case"><span className="k">{k}</span><div className="v">{children}</div></div>;
15
+ function Sheet() {
16
+ const [v, set] = React.useState({});
17
+ const b = (k, d = false) => ({ checked: v[k] ?? d, onChange: n => set(s => ({ ...s, [k]: n })) });
20
18
  return <div>
21
- <div style={{display:"grid",gridTemplateColumns:"200px 200px 1fr",gap:20,alignItems:"start"}}>
22
- <div>
23
- <span className="lbl">Switch — md</span>
24
- <div style={{display:"flex",flexDirection:"column",gap:12}}>
25
- <Switch label="Debug Mode" checked={a} onChange={setA}/>
26
- <Switch label="Auto-run on save" checked={b} onChange={setB}/>
27
- <Switch label="Locked by admin" checked disabled/>
28
- </div>
29
- </div>
30
- <div>
31
- <span className="lbl">Radio — md</span>
32
- <RadioGroup options={["New","Overwrite","Skip"]} value={r} onChange={setR}/>
33
- </div>
34
- <div>
35
- <span className="lbl">Checkbox — md / sm</span>
36
- <div style={{display:"flex",flexDirection:"column",gap:10}}>
37
- <Checkbox label="Send weekly summary" checked={c1} onChange={setC1}/>
38
- <Checkbox size="sm" label="Include archived rows" checked={c2} onChange={setC2}/>
39
- <Checkbox size="sm" label="Row selected" checked={c3==="all"} indeterminate={c3==="some"} onChange={()=>setC3(c3==="none"?"all":"none")}/>
40
- </div>
41
- </div>
42
- </div>
43
- <div style={{display:"grid",gridTemplateColumns:"200px 200px 1fr",gap:20,alignItems:"start",paddingTop:20,borderTop:"1px solid var(--border-subtle)",marginTop:20}}>
44
- <div>
45
- <span className="lbl">Switch — sm</span>
46
- <div style={{display:"flex",flexDirection:"column",gap:10}}>
47
- <Switch size="sm" label="Compact rows" checked={a} onChange={setA}/>
48
- <Switch size="sm" label="Show line numbers" checked={b} onChange={setB}/>
49
- </div>
50
- </div>
51
- <div>
52
- <span className="lbl">Radio — sm</span>
53
- <RadioGroup size="sm" options={["Ascending","Descending"]} value={r==="Skip"?"Ascending":"Descending"} onChange={()=>{}}/>
54
- </div>
55
- <div>
56
- <span className="lbl">SegmentedControl — md / sm · ViewToggle</span>
57
- <div style={{display:"flex",flexDirection:"column",gap:12,alignItems:"flex-start"}}>
58
- <SegmentedControl options={[{label:"List",icon:"list"},{label:"Grid",icon:"layout-grid"}]} value={s} onChange={setS}/>
59
- <SegmentedControl size="sm" options={["Last 7 days","Last 30 days","Quarter"]} value={t} onChange={setT}/>
60
- <ViewToggle value={v} onChange={setV}/>
61
- </div>
62
- </div>
63
- </div>
19
+ <div className="sec">Sizes &amp; states — sm · md · lg</div>
20
+ <Case k="on"><Switch size="sm" {...b("s1", true)} /><Switch {...b("s2", true)} /><Switch size="lg" {...b("s3", true)} /></Case>
21
+ <Case k="off"><Switch size="sm" {...b("s4")} /><Switch {...b("s5")} /><Switch size="lg" {...b("s6")} /></Case>
22
+ <Case k="disabled"><Switch size="sm" checked disabled /><Switch checked disabled /><Switch size="lg" checked disabled /></Case>
23
+ <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
+
25
+ <div className="sec">Semantic tone — danger off → success on</div>
26
+ <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
+ <Case k="off"><Switch size="sm" tone="semantic" {...b("t4")} /><Switch tone="semantic" {...b("t5")} /><Switch size="lg" tone="semantic" {...b("t6")} /></Case>
28
+
29
+ <div className="sec">Glyph in the knob — md · lg only (sm knob is 12px, too small for a glyph)</div>
30
+ <Case k="knobIcon check"><Switch knobIcon="check" {...b("g1", true)} /><Switch size="lg" knobIcon="check" {...b("g2", true)} /></Case>
31
+ <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
+ <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>
33
+ <Case k="knobText {Y, N}"><Switch knobText={{ on: "Y", off: "N" }} {...b("g7", true)} /><Switch size="lg" knobText={{ on: "Y", off: "N" }} {...b("g8", true)} /></Case>
34
+ <Case k="knobText {开, 关}"><Switch knobText={{ on: "开", off: "关" }} {...b("g9")} /><Switch size="lg" knobText={{ on: "开", off: "关" }} {...b("g10")} /></Case>
35
+ <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
+
37
+ <div className="sec">Text inside the pill — md · lg only</div>
38
+ <Case k="ON / OFF"><Switch insideOn="ON" insideOff="OFF" {...b("i1", true)} /><Switch size="lg" insideOn="ON" insideOff="OFF" {...b("i2", true)} /></Case>
39
+ <Case k="开 / 关"><Switch insideOn="开" insideOff="关" {...b("i3")} /><Switch size="lg" insideOn="开" insideOff="关" {...b("i4")} /></Case>
40
+ <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
+
42
+ <div className="sec">Captions beside — sm · md · lg (active side reads heading)</div>
43
+ <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
+ <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
+ <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
+
47
+ <div className="sec">Loading — sm · md · lg</div>
48
+ <Case k="loading · on"><Switch size="sm" checked loading /><Switch checked loading /><Switch size="lg" checked loading /></Case>
49
+ <Case k="loading · off"><Switch size="sm" loading /><Switch loading /><Switch size="lg" loading /></Case>
50
+ <Case k="semantic · loading"><Switch size="sm" tone="semantic" checked loading /><Switch tone="semantic" checked loading /><Switch size="lg" tone="semantic" checked loading /></Case>
51
+ <Case k="beforeChange → resolves 1.2s"><Switch size="sm" beforeChange={() => wait(1200)} {...b("a1", true)} /><Switch beforeChange={() => wait(1200)} {...b("a2", true)} /><Switch size="lg" knobIcon={{ on: "check", off: "x" }} beforeChange={() => wait(1200)} {...b("a3", true)} /></Case>
52
+ <Case k="beforeChange → rejects"><Switch size="sm" tone="semantic" beforeChange={() => wait(1200, false)} {...b("a4")} /><Switch tone="semantic" beforeChange={() => wait(1200, false)} {...b("a5")} /><Switch size="lg" tone="semantic" knobIcon={{ on: "check", off: "x" }} beforeChange={() => wait(1200, false)} {...b("a6")} /><span className="cap">stays put after the spinner</span></Case>
64
53
  </div>;
65
54
  }
66
55
  ReactDOM.createRoot(document.getElementById("root")).render(<Sheet/>);
67
- if (window.KBViewSource) setTimeout(function(){ KBViewSource.mount("#root", [{"name":"Switch.jsx","path":"../forms/Switch.jsx"},{"name":"Checkbox.jsx","path":"../forms/Checkbox.jsx"},{"name":"SegmentedControl.jsx","path":"../tabs/SegmentedControl.jsx"},{"name":"ViewToggle.jsx","path":"../tabs/ViewToggle.jsx"}]); }, 0);
56
+ if (window.KBViewSource) setTimeout(function(){ KBViewSource.mount("#root", [{"name":"Switch.jsx","path":"../forms/Switch.jsx"}]); }, 0);
68
57
  </script></body></html>