{"_id":"@cujuju/solidjs-seg-buttons","_rev":"3-94b7259b9382c0a0d0c00bcc5e3a3888","name":"@cujuju/solidjs-seg-buttons","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@cujuju/solidjs-seg-buttons","version":"0.1.0","keywords":["solidjs","segmented-control","toggle","button-group","radio"],"author":{"name":"Cujuju"},"license":"MIT","_id":"@cujuju/solidjs-seg-buttons@0.1.0","maintainers":[{"name":"cujuju","email":"cujuju@pm.me"}],"homepage":"https://github.com/Cujuju/solidjs-toolkit/tree/main/packages/seg-buttons","bugs":{"url":"https://github.com/Cujuju/solidjs-toolkit/issues"},"dist":{"shasum":"748ed9ac378e1190dc935b1edacd7cf673d878e8","tarball":"https://registry.npmjs.org/@cujuju/solidjs-seg-buttons/-/solidjs-seg-buttons-0.1.0.tgz","fileCount":13,"integrity":"sha512-tx8g+I/5jELYV/qTVKlLjFFtwJcQ9ztPsVmaf/uJjeoAnNddcLWM+m/X/ncTdGUVNZ9PsefgaeKGMlRpfWEHmw==","signatures":[{"sig":"MEUCIDc46xqKVHaNgZOXW8MUzZm5QJmYNpf3qOxVtSMYA9mLAiEAzV/A2SYhXhMzaFxoMP3PeagTKEENfbgyXi21IQ646Xk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":36475},"main":"./dist/index.js","type":"module","_from":"file:cujuju-solidjs-seg-buttons-0.1.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"solid":"./src/index.ts","types":"./dist/index.d.ts","import":"./dist/index.js"},"./styles.css":"./src/styles.css"},"scripts":{"build":"vite build"},"_npmUser":{"name":"cujuju","email":"cujuju@pm.me"},"_resolved":"C:\\Users\\shawn\\AppData\\Local\\Temp\\b2752566ff66c659e21db0d944936f5a\\cujuju-solidjs-seg-buttons-0.1.0.tgz","_integrity":"sha512-tx8g+I/5jELYV/qTVKlLjFFtwJcQ9ztPsVmaf/uJjeoAnNddcLWM+m/X/ncTdGUVNZ9PsefgaeKGMlRpfWEHmw==","repository":{"url":"git+https://github.com/Cujuju/solidjs-toolkit.git","type":"git","directory":"packages/seg-buttons"},"_npmVersion":"11.12.1","description":"Segmented button control for SolidJS — controlled or uncontrolled, size presets, full a11y, RTL-ready.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"25.8.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"solid-js":">=1.7.0"},"_npmOperationalInternal":{"tmp":"tmp/solidjs-seg-buttons_0.1.0_1777341472308_0.2636620880028562","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@cujuju/solidjs-seg-buttons","version":"0.2.0","keywords":["solidjs","segmented-control","toggle","button-group","radio"],"author":{"name":"Cujuju"},"license":"MIT","_id":"@cujuju/solidjs-seg-buttons@0.2.0","maintainers":[{"name":"cujuju","email":"cujuju@pm.me"}],"homepage":"https://github.com/Cujuju/solidjs-toolkit/tree/main/packages/seg-buttons","bugs":{"url":"https://github.com/Cujuju/solidjs-toolkit/issues"},"dist":{"shasum":"3e9466049ca7adb35b22c536b93e8b6092e1d001","tarball":"https://registry.npmjs.org/@cujuju/solidjs-seg-buttons/-/solidjs-seg-buttons-0.2.0.tgz","fileCount":14,"integrity":"sha512-Nyzk5Sp9zYURlTymXPIFxgz9WrJOAGk7DeP8hxuuLu/gIxfliDLKiTbZiYb79O3QMbeVFENm1ajbsfebcO78KQ==","signatures":[{"sig":"MEUCIGWOabUp1z8TLZbXhxPGggJ9njp8oG1QR8KY7CBO2vd7AiEAoSW57A4e87XgfTt0rACQidUk3Db2UM1RfzWwMjW/XLc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":50525},"main":"./dist/index.js","type":"module","_from":"file:cujuju-solidjs-seg-buttons-0.2.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"solid":"./src/index.ts","types":"./dist/index.d.ts","import":"./dist/index.js"},"./styles.css":"./src/styles.css"},"scripts":{"test":"vitest run","build":"vite build","test:watch":"vitest"},"_npmUser":{"name":"cujuju","email":"cujuju@pm.me"},"_resolved":"/tmp/023f0ac30bf293814af4e1a13bcd668c/cujuju-solidjs-seg-buttons-0.2.0.tgz","_integrity":"sha512-Nyzk5Sp9zYURlTymXPIFxgz9WrJOAGk7DeP8hxuuLu/gIxfliDLKiTbZiYb79O3QMbeVFENm1ajbsfebcO78KQ==","repository":{"url":"git+https://github.com/Cujuju/solidjs-toolkit.git","type":"git","directory":"packages/seg-buttons"},"_npmVersion":"12.0.1","description":"Segmented button control for SolidJS — controlled or uncontrolled, size presets, full a11y, RTL-ready.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^24.0.0","vitest":"^3.2.4","vite-plugin-solid":"^2.11.12","@testing-library/jest-dom":"^6.9.1"},"peerDependencies":{"solid-js":">=1.7.0"},"_npmOperationalInternal":{"tmp":"tmp/solidjs-seg-buttons_0.2.0_1784887078865_0.006336648945725498","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"_id":"@cujuju/solidjs-seg-buttons@0.3.0","bugs":"https://github.com/Cujuju/solidjs-toolkit/issues","dist":{"shasum":"2c639775866318c200573c2725b7cb93cb60c880","tarball":"https://registry.npmjs.org/@cujuju/solidjs-seg-buttons/-/solidjs-seg-buttons-0.3.0.tgz","fileCount":16,"integrity":"sha512-gPN15YKfiDilD3AeLt1i/022Z2rgkj+NK6GkCnHVx6RUDuWOTzjezh+jvEc2U5hmFyi2iRDOe1ALQ3uB0MYATg==","signatures":[{"sig":"MEQCIAh6gutFISaT3BAT33lyDCD7n5d35MUiSpGbQeqZrT8wAiBFG9+XVTlQpKDFKPdtxsSW+7HYphhVHpDxI69giTZ8oQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCNj9rPI7J0mxthJLJ4wXs3dDCJV4zuhr6ZAwrIbkjAtQIhALQcgxYF08LogrG5t1JkC150zsYsLi0iz3o66ZwNVpcS"}],"unpackedSize":88078},"main":"./dist/index.js","name":"@cujuju/solidjs-seg-buttons","type":"module","types":"./dist/index.d.ts","author":"Cujuju","module":"./dist/index.js","exports":{".":{"solid":"./src/index.ts","types":"./dist/index.d.ts","import":"./dist/index.js"},"./style.css":"./dist/style.css","./styles.css":"./src/styles.css"},"license":"MIT","scripts":{"test":"vitest run","build":"vite build","test:watch":"vitest"},"version":"0.3.0","_npmUser":{"name":"cujuju","email":"cujuju@pm.me"},"homepage":"https://github.com/Cujuju/solidjs-toolkit/tree/main/packages/seg-buttons","keywords":["solidjs","segmented-control","toggle","button-group","radio"],"repository":{"url":"https://github.com/Cujuju/solidjs-toolkit.git","type":"git","directory":"packages/seg-buttons"},"description":"Segmented button control for SolidJS — controlled or uncontrolled, size presets, full a11y, RTL-ready.","directories":{},"maintainers":[{"name":"cujuju","email":"cujuju@pm.me"}],"sideEffects":["**/*.css","./src/index.ts","./dist/index.js"],"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^24.0.0","vitest":"^3.2.4","vite-plugin-solid":"^2.11.12","@testing-library/jest-dom":"^6.9.1"},"peerDependencies":{"solid-js":">=1.7.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/solidjs-seg-buttons_0.3.0_1791059623006_0.06898544744303137"}}},"time":{"created":"2026-04-28T01:57:52.245Z","modified":"2026-10-03T20:33:43.310Z","0.1.0":"2026-04-28T01:57:52.449Z","0.2.0":"2026-07-24T09:57:58.990Z","0.3.0":"2026-10-03T20:33:43.090Z"},"bugs":"https://github.com/Cujuju/solidjs-toolkit/issues","author":"Cujuju","license":"MIT","homepage":"https://github.com/Cujuju/solidjs-toolkit/tree/main/packages/seg-buttons","keywords":["solidjs","segmented-control","toggle","button-group","radio"],"repository":{"url":"https://github.com/Cujuju/solidjs-toolkit.git","type":"git","directory":"packages/seg-buttons"},"description":"Segmented button control for SolidJS — controlled or uncontrolled, size presets, full a11y, RTL-ready.","maintainers":[{"name":"cujuju","email":"cujuju@pm.me"}],"readme":"# @cujuju/solidjs-seg-buttons\n\nSegmented button control for SolidJS. Controlled or uncontrolled. Full a11y. RTL-ready via CSS logical properties.\n\n## Install\n\n```\npnpm add @cujuju/solidjs-seg-buttons\n```\n\nThe package ships its own stylesheet, auto-imported via the entrypoint. If your bundler doesn't pick up the side-effect import, add it manually:\n\n```ts\nimport '@cujuju/solidjs-seg-buttons/styles.css';\n```\n\n## Usage\n\n### Uncontrolled (caller manages state per button)\n\n```tsx\nimport { SegGroup, SegButton } from '@cujuju/solidjs-seg-buttons';\n\nconst [tf, setTf] = createSignal('day');\n\n<SegGroup ariaLabel=\"Timeframe\">\n  <SegButton label=\"Day\"   active={tf() === 'day'}   onClick={() => setTf('day')} />\n  <SegButton label=\"Week\"  active={tf() === 'week'}  onClick={() => setTf('week')} />\n  <SegButton label=\"Month\" active={tf() === 'month'} onClick={() => setTf('month')} />\n</SegGroup>\n```\n\n### Controlled (SegGroup owns the selected value)\n\n```tsx\n<SegGroup value={tf()} onChange={setTf} ariaLabel=\"Timeframe\">\n  <SegButton value=\"day\"   label=\"Day\" />\n  <SegButton value=\"week\"  label=\"Week\" />\n  <SegButton value=\"month\" label=\"Month\" />\n</SegGroup>\n```\n\nWhen `SegGroup.value` is set, `SegButton`s read state from context and call `onChange` with their own `value` prop on click. Falls back to `active`/`onClick` props when `SegGroup.value` is undefined or the button has no `value`.\n\n### Radiogroup semantics (recommended for mutually-exclusive selections)\n\n```tsx\n<SegGroup role=\"radiogroup\" value={tf()} onChange={setTf} ariaLabel=\"Timeframe\">\n  <SegButton value=\"day\" label=\"Day\" />\n  <SegButton value=\"week\" label=\"Week\" />\n</SegGroup>\n```\n\n- `role=\"radiogroup\"` on the wrapper; each SegButton emits `role=\"radio\"` with `aria-checked`\n- Roving tabindex: exactly one button is Tab-focusable — the active button if it is enabled, else the first enabled button (none when every option is disabled)\n- ArrowLeft / ArrowRight move focus (and selection) between siblings, skipping disabled ones; mirrored under `dir=\"rtl\"`\n\nThe default is `role=\"group\"` with `aria-pressed` on each button — simpler and works fine for non-exclusive toggle patterns.\n\n## API\n\n### `<SegGroup>`\n\n| Prop | Default | Description |\n|---|---|---|\n| `value` | — | Controlled-mode selected value. If set, enables context-driven selection. |\n| `onChange(value)` | — | Called when a child SegButton with a `value` is clicked. |\n| `role` | `'group'` | `'group'` (aria-pressed mode) or `'radiogroup'` (ARIA radio mode). |\n| `ariaLabel` | — | Describes the group for screen readers. |\n| `class` | — | Additional class on the wrapper span. |\n\n### `<SegButton>`\n\n| Prop | Default | Description |\n|---|---|---|\n| `label` | (required) | Button label. Also used for bold-width reservation. |\n| `active` | `false` | Selected state (uncontrolled mode). |\n| `onClick` | — | Click handler (uncontrolled mode). |\n| `value` | — | This button's value in controlled mode. |\n| `size` | `'md'` | Preset — `'xs'` / `'sm'` / `'md'`. |\n| `height` | (preset) | Raw override. Numbers → px. |\n| `paddingX` | (preset) | Raw override. |\n| `fontSize` | (preset) | Raw override. |\n| `minWidth` | — | Optional px minimum width. |\n| `reserveBoldWidth` | `true` | Reserves bold-weight width so active state doesn't shift layout. |\n| `children` | — | Alternate content (icon + text, etc.). Falls back to `label`. |\n| `disabled` | `false` | Non-interactive, dimmed. |\n| `ariaLabel` | — | Screen-reader label override. |\n| `title` | — | Hover hint — rendered through a registered tooltip host, else a native `title`. |\n| `tooltipDelayMs` | (shared default, 600) | Overrides the host's show delay for this button, ms. Host path only. |\n| `class` | — | Additional class. |\n\n### Tooltip host\n\n`title` renders as a native `title` unless a tooltip component is registered. Register one once at app boot to upgrade every SegButton hint (the native `title` is then suppressed, so hints never double up):\n\n```ts\nimport { KvTooltip } from '@cujuju/solidjs-kv-tooltip';\nimport { setSegTooltipHost, setSegTooltipDefaults } from '@cujuju/solidjs-seg-buttons';\n\nsetSegTooltipHost(KvTooltip);                             // `null` clears it\nsetSegTooltipDefaults({ delayMs: 400, maxWidth: 240 });   // merges over { delayMs: 600, maxWidth: 300 }\n```\n\n| Export | Description |\n|---|---|\n| `setSegTooltipHost(host \\| null)` | Register or clear the hint renderer. Already-mounted buttons switch in place. |\n| `setSegTooltipDefaults(partial)` | Shared `delayMs` / `maxWidth` for every hint. |\n| `segTooltipDefaults()` | Current defaults (reactive). |\n| `SegTooltipHost` / `SegTooltipHostProps` | Structural contract a host component must satisfy (`KvTooltip` does). |\n| `SegTooltipDefaults` | `{ delayMs, maxWidth }`. |\n\n## Theming\n\nOverride any of these CSS custom properties at any ancestor level:\n\n```css\n:root {\n  --seg-active-bg: #10b981;\n  --seg-active-border: #059669;\n  --seg-active-text: #ffffff;\n  --seg-active-weight: 600;\n\n  --seg-inactive-bg: #1e293b;\n  --seg-inactive-border: #334155;\n  --seg-inactive-text: #94a3b8;\n\n  --seg-disabled-opacity: 0.4;\n  /* Recommended override point for a brighter ring: */\n  --seg-focus-ring-color: color-mix(in srgb, var(--seg-inactive-border) 45%, #fff);\n  --seg-focus-ring: 1px solid var(--seg-focus-ring-color);\n  --seg-focus-ring-offset: -1px;\n  --seg-radius: 4px;\n}\n```\n\n### Intent variants (extension pattern)\n\nThe library ships with one accent. For red/green/etc. variants, define a scoped override:\n\n```css\n.seg-danger {\n  --seg-active-bg: #fee2e2;\n  --seg-active-border: #ef4444;\n  --seg-active-text: #dc2626;\n}\n```\n\nThen apply the class to the `SegGroup` or individual `SegButton`:\n\n```tsx\n<SegButton class=\"seg-danger\" active={mode() === 'delete'} onClick={...} label=\"Delete\" />\n```\n\n## RTL\n\nAll corner-rounding and button-overlap uses CSS logical properties (`border-start-start-radius`, `margin-inline-start`, etc.), so RTL layouts flip correctly when `dir=\"rtl\"` is set on any ancestor.\n\n## Touch targets\n\nPreset sizes `xs` (20px) and `sm` (24px) fall below WCAG 2.1 AA minimum touch target size of 44×44 CSS px. For touch-primary UIs, use `size=\"md\"` (28px) with a `height` override:\n\n```tsx\n<SegButton height={44} paddingX=\"1rem\" label=\"Mobile\" active={...} onClick={...} />\n```\n\n## License\n\nMIT\n","readmeFilename":""}