soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
import { Provider, context, type WithRefOpts } from '$soma/provider';
|
soma: audit fixes — 84 issues across 25 components, Table complete
Table component:
- Complete state manager: sorting, filtering, pagination, selection,
column pinning (sticky), column sizing, expandable rows (sub-rows +
detail panels), column visibility
- Provider renders <table> with translated aria-label
- Sorting opt-in per column, consumer places sort buttons
- filteredRowCount/totalRowCount for correct pagination count
- Sub-row IDs hierarchical (parentId.subIndex), no collisions
- Production-grade test page (Swiss Industrial design)
- Full README with all features documented
Critical fixes (10):
- Toast: memory leaks (timer + hotkey listener cleanup via $effect)
- Toast: restartTimer() method for promise-based toasts
- ScrollArea: type='always' now works (check order fix)
- ScrollArea: thumb click no longer triggers track jump
- Tooltip: no crash without <Tooltip.Group> (ctx.getOr)
- Combobox: click-outside-to-close fixed (isValidEvent)
- Popover: stray 'n' character removed from popover.svelte
- TreeView: ARIA ownership fixed (role=treeitem on Branch, not Control)
- Splitter: documented required array spread for reactivity
High fixes (14):
- Checkbox: group disabled/name propagation + checked sync via $effect
- Select: aria-labelledby on content, aria-disabled on items
- Stepper: aria-controls + aria-labelledby cross-linking
- TagsInput: highlightPrev returns to input, role on Control/Item
- Editable: Preview role=button + aria-label
- Pagination: translated aria-label on items
- RadioGroup: removed unused Soma import
Medium fixes (60):
- registerContract() added to all 25 components
- Dead config=getSoma() removed from 7 providers
- Dead imports removed (Tooltip, Popover, Slider, Combobox)
- Dialog: aria-modal conditional on modal prop
- Slider: pointer capture release + onpointercancel
- Popover: hover timeout cleanup, aria-modal support
- Tabs: inactive content hidden + aria-hidden + tabindex=-1
- ToggleGroup: aria-orientation + roving tabindex fallback
- Toolbar: data-disabled on Button
- Stepper: Content tabindex
- TreeView: RTL keyboard support (expand/collapse key swap)
- NumberField: Enter key commit, clampOnBlur, allowMouseWheel, scrubber a11y
- Toast: data-state on root, aria-live on viewport
- ScrollArea: scrollbar aria-label + tabindex
- Collapsible: part root (not provider), aria-controls, role=region
- Tooltip: removed dead provider part from attrs
Architecture:
- COMPONENT_GUIDE.md: 14 audit-derived rules (A1-A14)
- Checklist expanded from 15 to 23 steps
- 8 new HTML primitive types (Table, THead, TBody, TFoot, TR, TH, TD, Caption)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
import { createAttrs, registerContract, boolToEmptyStrOrUndef } from '$soma/attrs';
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
import { readableActive, state, type Active, type ActiveProps } from '$soma/reactive';
|
|
|
|
|
import type { Direction } from '$soma/types';
|
|
|
|
|
import { isBrowser } from '$soma/dom';
|
soma: audit fixes — 84 issues across 25 components, Table complete
Table component:
- Complete state manager: sorting, filtering, pagination, selection,
column pinning (sticky), column sizing, expandable rows (sub-rows +
detail panels), column visibility
- Provider renders <table> with translated aria-label
- Sorting opt-in per column, consumer places sort buttons
- filteredRowCount/totalRowCount for correct pagination count
- Sub-row IDs hierarchical (parentId.subIndex), no collisions
- Production-grade test page (Swiss Industrial design)
- Full README with all features documented
Critical fixes (10):
- Toast: memory leaks (timer + hotkey listener cleanup via $effect)
- Toast: restartTimer() method for promise-based toasts
- ScrollArea: type='always' now works (check order fix)
- ScrollArea: thumb click no longer triggers track jump
- Tooltip: no crash without <Tooltip.Group> (ctx.getOr)
- Combobox: click-outside-to-close fixed (isValidEvent)
- Popover: stray 'n' character removed from popover.svelte
- TreeView: ARIA ownership fixed (role=treeitem on Branch, not Control)
- Splitter: documented required array spread for reactivity
High fixes (14):
- Checkbox: group disabled/name propagation + checked sync via $effect
- Select: aria-labelledby on content, aria-disabled on items
- Stepper: aria-controls + aria-labelledby cross-linking
- TagsInput: highlightPrev returns to input, role on Control/Item
- Editable: Preview role=button + aria-label
- Pagination: translated aria-label on items
- RadioGroup: removed unused Soma import
Medium fixes (60):
- registerContract() added to all 25 components
- Dead config=getSoma() removed from 7 providers
- Dead imports removed (Tooltip, Popover, Slider, Combobox)
- Dialog: aria-modal conditional on modal prop
- Slider: pointer capture release + onpointercancel
- Popover: hover timeout cleanup, aria-modal support
- Tabs: inactive content hidden + aria-hidden + tabindex=-1
- ToggleGroup: aria-orientation + roving tabindex fallback
- Toolbar: data-disabled on Button
- Stepper: Content tabindex
- TreeView: RTL keyboard support (expand/collapse key swap)
- NumberField: Enter key commit, clampOnBlur, allowMouseWheel, scrubber a11y
- Toast: data-state on root, aria-live on viewport
- ScrollArea: scrollbar aria-label + tabindex
- Collapsible: part root (not provider), aria-controls, role=region
- Tooltip: removed dead provider part from attrs
Architecture:
- COMPONENT_GUIDE.md: 14 audit-derived rules (A1-A14)
- Checklist expanded from 15 to 23 steps
- 8 new HTML primitive types (Table, THead, TBody, TFoot, TR, TH, TD, Caption)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
|
|
|
|
|
const attrs = createAttrs({
|
|
|
|
|
component: 'scroll-area',
|
|
|
|
|
parts: ['root', 'viewport', 'scrollbar', 'thumb', 'corner'] as const,
|
|
|
|
|
});
|
|
|
|
|
|
soma: audit fixes — 84 issues across 25 components, Table complete
Table component:
- Complete state manager: sorting, filtering, pagination, selection,
column pinning (sticky), column sizing, expandable rows (sub-rows +
detail panels), column visibility
- Provider renders <table> with translated aria-label
- Sorting opt-in per column, consumer places sort buttons
- filteredRowCount/totalRowCount for correct pagination count
- Sub-row IDs hierarchical (parentId.subIndex), no collisions
- Production-grade test page (Swiss Industrial design)
- Full README with all features documented
Critical fixes (10):
- Toast: memory leaks (timer + hotkey listener cleanup via $effect)
- Toast: restartTimer() method for promise-based toasts
- ScrollArea: type='always' now works (check order fix)
- ScrollArea: thumb click no longer triggers track jump
- Tooltip: no crash without <Tooltip.Group> (ctx.getOr)
- Combobox: click-outside-to-close fixed (isValidEvent)
- Popover: stray 'n' character removed from popover.svelte
- TreeView: ARIA ownership fixed (role=treeitem on Branch, not Control)
- Splitter: documented required array spread for reactivity
High fixes (14):
- Checkbox: group disabled/name propagation + checked sync via $effect
- Select: aria-labelledby on content, aria-disabled on items
- Stepper: aria-controls + aria-labelledby cross-linking
- TagsInput: highlightPrev returns to input, role on Control/Item
- Editable: Preview role=button + aria-label
- Pagination: translated aria-label on items
- RadioGroup: removed unused Soma import
Medium fixes (60):
- registerContract() added to all 25 components
- Dead config=getSoma() removed from 7 providers
- Dead imports removed (Tooltip, Popover, Slider, Combobox)
- Dialog: aria-modal conditional on modal prop
- Slider: pointer capture release + onpointercancel
- Popover: hover timeout cleanup, aria-modal support
- Tabs: inactive content hidden + aria-hidden + tabindex=-1
- ToggleGroup: aria-orientation + roving tabindex fallback
- Toolbar: data-disabled on Button
- Stepper: Content tabindex
- TreeView: RTL keyboard support (expand/collapse key swap)
- NumberField: Enter key commit, clampOnBlur, allowMouseWheel, scrubber a11y
- Toast: data-state on root, aria-live on viewport
- ScrollArea: scrollbar aria-label + tabindex
- Collapsible: part root (not provider), aria-controls, role=region
- Tooltip: removed dead provider part from attrs
Architecture:
- COMPONENT_GUIDE.md: 14 audit-derived rules (A1-A14)
- Checklist expanded from 15 to 23 steps
- 8 new HTML primitive types (Table, THead, TBody, TFoot, TR, TH, TD, Caption)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
registerContract({ name: 'scroll-area', version: 1, parts: {
|
|
|
|
|
'root': [{ attr: 'data-overflow-x', description: 'Horizontal overflow' }, { attr: 'data-overflow-y', description: 'Vertical overflow' }],
|
|
|
|
|
'viewport': [{ attr: 'data-at-top', description: 'At top' }, { attr: 'data-at-bottom', description: 'At bottom' }, { attr: 'data-at-left', description: 'At left' }, { attr: 'data-at-right', description: 'At right' }],
|
|
|
|
|
'scrollbar': [{ attr: 'data-state', values: ['visible', 'hidden'], description: 'Visibility' }, { attr: 'data-orientation', values: ['horizontal', 'vertical'], description: 'Orientation' }, { attr: 'data-hover', description: 'Hover' }, { attr: 'data-dragging', description: 'Dragging' }],
|
|
|
|
|
'thumb': [{ attr: 'data-state', values: ['visible', 'hidden'], description: 'Visibility' }, { attr: 'data-orientation', values: ['horizontal', 'vertical'], description: 'Orientation' }],
|
|
|
|
|
'corner': [{ attr: 'data-state', values: ['visible', 'hidden'], description: 'Visibility' }],
|
|
|
|
|
}});
|
|
|
|
|
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
export type ScrollAreaType = 'hover' | 'scroll' | 'auto' | 'always';
|
|
|
|
|
|
|
|
|
|
// ── Root ─────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
interface ScrollAreaOpts
|
|
|
|
|
extends WithRefOpts,
|
|
|
|
|
ActiveProps<{
|
|
|
|
|
type: ScrollAreaType;
|
|
|
|
|
scrollHideDelay: number;
|
|
|
|
|
dir: Direction;
|
|
|
|
|
}> {}
|
|
|
|
|
|
|
|
|
|
export class ScrollAreaProvider extends Provider<ScrollAreaOpts> {
|
|
|
|
|
static readonly ctx = context<ScrollAreaProvider>('ScrollArea');
|
|
|
|
|
|
|
|
|
|
static from(opts: ScrollAreaOpts) {
|
|
|
|
|
return new ScrollAreaProvider(opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Viewport tracking
|
|
|
|
|
viewportRef = state<HTMLElement | null>(null);
|
|
|
|
|
contentWidth = $state(0);
|
|
|
|
|
contentHeight = $state(0);
|
|
|
|
|
viewportWidth = $state(0);
|
|
|
|
|
viewportHeight = $state(0);
|
|
|
|
|
scrollTop = $state(0);
|
|
|
|
|
scrollLeft = $state(0);
|
|
|
|
|
|
|
|
|
|
private resizeObserver: ResizeObserver | null = null;
|
|
|
|
|
|
|
|
|
|
private constructor(opts: ScrollAreaOpts) {
|
|
|
|
|
super(opts, 'ScrollArea', 'root', attrs.root, ScrollAreaProvider.ctx);
|
|
|
|
|
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Overflow detection ───────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
readonly hasOverflowX = $derived.by(() => this.contentWidth > this.viewportWidth);
|
|
|
|
|
readonly hasOverflowY = $derived.by(() => this.contentHeight > this.viewportHeight);
|
|
|
|
|
|
|
|
|
|
// ── Position tracking ────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
readonly isAtTop = $derived.by(() => this.scrollTop <= 0);
|
|
|
|
|
readonly isAtBottom = $derived.by(
|
|
|
|
|
() => this.scrollTop >= this.contentHeight - this.viewportHeight - 1,
|
|
|
|
|
);
|
|
|
|
|
readonly isAtLeft = $derived.by(() => this.scrollLeft <= 0);
|
|
|
|
|
readonly isAtRight = $derived.by(
|
|
|
|
|
() => this.scrollLeft >= this.contentWidth - this.viewportWidth - 1,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// ── Scroll progress (0..1) ───────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
getScrollProgressY(): number {
|
|
|
|
|
const max = this.contentHeight - this.viewportHeight;
|
|
|
|
|
return max <= 0 ? 0 : this.scrollTop / max;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getScrollProgressX(): number {
|
|
|
|
|
const max = this.contentWidth - this.viewportWidth;
|
|
|
|
|
return max <= 0 ? 0 : this.scrollLeft / max;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Viewport setup ───────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
setupViewport(el: HTMLElement | null) {
|
|
|
|
|
this.viewportRef.current = el;
|
|
|
|
|
this.cleanupResize();
|
|
|
|
|
|
|
|
|
|
if (!el || !isBrowser) return;
|
|
|
|
|
|
|
|
|
|
const update = () => {
|
|
|
|
|
this.viewportWidth = el.clientWidth;
|
|
|
|
|
this.viewportHeight = el.clientHeight;
|
|
|
|
|
this.contentWidth = el.scrollWidth;
|
|
|
|
|
this.contentHeight = el.scrollHeight;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
update();
|
|
|
|
|
|
|
|
|
|
this.resizeObserver = new ResizeObserver(update);
|
|
|
|
|
this.resizeObserver.observe(el);
|
|
|
|
|
if (el.firstElementChild) {
|
|
|
|
|
this.resizeObserver.observe(el.firstElementChild);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleScroll(el: HTMLElement) {
|
|
|
|
|
this.scrollTop = el.scrollTop;
|
|
|
|
|
this.scrollLeft = el.scrollLeft;
|
|
|
|
|
// Re-measure in case content changed
|
|
|
|
|
this.contentWidth = el.scrollWidth;
|
|
|
|
|
this.contentHeight = el.scrollHeight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private cleanupResize() {
|
|
|
|
|
this.resizeObserver?.disconnect();
|
|
|
|
|
this.resizeObserver = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
this.assertProps({
|
|
|
|
|
...this.baseProps,
|
|
|
|
|
style: {
|
|
|
|
|
position: 'relative',
|
|
|
|
|
'--soma-scroll-area-corner-width':
|
|
|
|
|
this.hasOverflowX && this.hasOverflowY ? 'var(--soma-scroll-area-scrollbar-size, 8px)' : '0px',
|
|
|
|
|
'--soma-scroll-area-corner-height':
|
|
|
|
|
this.hasOverflowX && this.hasOverflowY ? 'var(--soma-scroll-area-scrollbar-size, 8px)' : '0px',
|
|
|
|
|
},
|
|
|
|
|
'data-overflow-x': boolToEmptyStrOrUndef(this.hasOverflowX),
|
|
|
|
|
'data-overflow-y': boolToEmptyStrOrUndef(this.hasOverflowY),
|
|
|
|
|
} as const),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Viewport ────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
interface ScrollAreaViewportOpts extends WithRefOpts {}
|
|
|
|
|
|
|
|
|
|
export class ScrollAreaViewportProvider extends Provider<ScrollAreaViewportOpts> {
|
|
|
|
|
static from(opts: ScrollAreaViewportOpts) {
|
|
|
|
|
return new ScrollAreaViewportProvider(opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly provider: ScrollAreaProvider;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
|
|
|
|
|
private constructor(opts: ScrollAreaViewportOpts) {
|
|
|
|
|
super(opts, 'ScrollArea', 'viewport', attrs.viewport, undefined, (el) => {
|
|
|
|
|
this.provider.setupViewport(el);
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
});
|
|
|
|
|
this.provider = ScrollAreaProvider.ctx.get();
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly onscroll = (e: Event) => {
|
|
|
|
|
this.provider.handleScroll(e.currentTarget as HTMLElement);
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
};
|
|
|
|
|
|
|
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
this.assertProps({
|
|
|
|
|
...this.baseProps,
|
|
|
|
|
style: {
|
|
|
|
|
overflow: 'scroll',
|
|
|
|
|
'scrollbar-width': 'none',
|
|
|
|
|
},
|
|
|
|
|
'data-at-top': boolToEmptyStrOrUndef(this.provider.isAtTop),
|
|
|
|
|
'data-at-bottom': boolToEmptyStrOrUndef(this.provider.isAtBottom),
|
|
|
|
|
'data-at-left': boolToEmptyStrOrUndef(this.provider.isAtLeft),
|
|
|
|
|
'data-at-right': boolToEmptyStrOrUndef(this.provider.isAtRight),
|
|
|
|
|
'data-overflow-x': boolToEmptyStrOrUndef(this.provider.hasOverflowX),
|
|
|
|
|
'data-overflow-y': boolToEmptyStrOrUndef(this.provider.hasOverflowY),
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
onscroll: this.onscroll,
|
|
|
|
|
} as const),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Scrollbar ───────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
type Orientation = 'horizontal' | 'vertical';
|
|
|
|
|
|
|
|
|
|
interface ScrollAreaScrollbarOpts
|
|
|
|
|
extends WithRefOpts,
|
|
|
|
|
ActiveProps<{
|
|
|
|
|
orientation: Orientation;
|
|
|
|
|
}> {}
|
|
|
|
|
|
|
|
|
|
export class ScrollAreaScrollbarProvider extends Provider<ScrollAreaScrollbarOpts> {
|
|
|
|
|
static readonly ctx = context<ScrollAreaScrollbarProvider>('ScrollAreaScrollbar');
|
|
|
|
|
|
|
|
|
|
static from(opts: ScrollAreaScrollbarOpts) {
|
|
|
|
|
return new ScrollAreaScrollbarProvider(opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly provider: ScrollAreaProvider;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
|
|
|
|
|
// Visibility state
|
|
|
|
|
visible = $state(false);
|
|
|
|
|
private hideTimer: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
|
hovering = $state(false);
|
|
|
|
|
dragging = $state(false);
|
|
|
|
|
|
|
|
|
|
private constructor(opts: ScrollAreaScrollbarOpts) {
|
|
|
|
|
super(opts, 'ScrollArea', 'scrollbar', attrs.scrollbar, ScrollAreaScrollbarProvider.ctx);
|
|
|
|
|
this.provider = ScrollAreaProvider.ctx.get();
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private get isVertical(): boolean {
|
|
|
|
|
return this.opts.orientation.current === 'vertical';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private get hasOverflow(): boolean {
|
|
|
|
|
return this.isVertical ? this.provider.hasOverflowY : this.provider.hasOverflowX;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Whether the scrollbar should be displayed based on type and state. */
|
|
|
|
|
readonly shouldShow = $derived.by(() => {
|
|
|
|
|
const type = this.provider.opts.type.current;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
if (type === 'always') return true;
|
soma: audit fixes — 84 issues across 25 components, Table complete
Table component:
- Complete state manager: sorting, filtering, pagination, selection,
column pinning (sticky), column sizing, expandable rows (sub-rows +
detail panels), column visibility
- Provider renders <table> with translated aria-label
- Sorting opt-in per column, consumer places sort buttons
- filteredRowCount/totalRowCount for correct pagination count
- Sub-row IDs hierarchical (parentId.subIndex), no collisions
- Production-grade test page (Swiss Industrial design)
- Full README with all features documented
Critical fixes (10):
- Toast: memory leaks (timer + hotkey listener cleanup via $effect)
- Toast: restartTimer() method for promise-based toasts
- ScrollArea: type='always' now works (check order fix)
- ScrollArea: thumb click no longer triggers track jump
- Tooltip: no crash without <Tooltip.Group> (ctx.getOr)
- Combobox: click-outside-to-close fixed (isValidEvent)
- Popover: stray 'n' character removed from popover.svelte
- TreeView: ARIA ownership fixed (role=treeitem on Branch, not Control)
- Splitter: documented required array spread for reactivity
High fixes (14):
- Checkbox: group disabled/name propagation + checked sync via $effect
- Select: aria-labelledby on content, aria-disabled on items
- Stepper: aria-controls + aria-labelledby cross-linking
- TagsInput: highlightPrev returns to input, role on Control/Item
- Editable: Preview role=button + aria-label
- Pagination: translated aria-label on items
- RadioGroup: removed unused Soma import
Medium fixes (60):
- registerContract() added to all 25 components
- Dead config=getSoma() removed from 7 providers
- Dead imports removed (Tooltip, Popover, Slider, Combobox)
- Dialog: aria-modal conditional on modal prop
- Slider: pointer capture release + onpointercancel
- Popover: hover timeout cleanup, aria-modal support
- Tabs: inactive content hidden + aria-hidden + tabindex=-1
- ToggleGroup: aria-orientation + roving tabindex fallback
- Toolbar: data-disabled on Button
- Stepper: Content tabindex
- TreeView: RTL keyboard support (expand/collapse key swap)
- NumberField: Enter key commit, clampOnBlur, allowMouseWheel, scrubber a11y
- Toast: data-state on root, aria-live on viewport
- ScrollArea: scrollbar aria-label + tabindex
- Collapsible: part root (not provider), aria-controls, role=region
- Tooltip: removed dead provider part from attrs
Architecture:
- COMPONENT_GUIDE.md: 14 audit-derived rules (A1-A14)
- Checklist expanded from 15 to 23 steps
- 8 new HTML primitive types (Table, THead, TBody, TFoot, TR, TH, TD, Caption)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
if (!this.hasOverflow) return false;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
if (type === 'auto') return true;
|
|
|
|
|
if (type === 'hover') return this.visible;
|
|
|
|
|
if (type === 'scroll') return this.visible;
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/** Show the scrollbar (for hover/scroll modes). */
|
|
|
|
|
show() {
|
|
|
|
|
this.clearHideTimer();
|
|
|
|
|
this.visible = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Schedule hiding the scrollbar after delay. */
|
|
|
|
|
scheduleHide() {
|
|
|
|
|
this.clearHideTimer();
|
|
|
|
|
const delay = this.provider.opts.scrollHideDelay.current;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
this.hideTimer = setTimeout(() => {
|
|
|
|
|
if (!this.hovering && !this.dragging) {
|
|
|
|
|
this.visible = false;
|
|
|
|
|
}
|
|
|
|
|
}, delay);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private clearHideTimer() {
|
|
|
|
|
if (this.hideTimer) {
|
|
|
|
|
clearTimeout(this.hideTimer);
|
|
|
|
|
this.hideTimer = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly onpointerenter = () => {
|
|
|
|
|
this.hovering = true;
|
|
|
|
|
this.show();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
readonly onpointerleave = () => {
|
|
|
|
|
this.hovering = false;
|
|
|
|
|
if (!this.dragging) this.scheduleHide();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** Handle click on the track (not thumb) to scroll to that position. */
|
|
|
|
|
readonly onclick = (e: MouseEvent) => {
|
|
|
|
|
const el = this.opts.ref.current;
|
|
|
|
|
const viewport = this.provider.viewportRef.current;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
if (!el || !viewport) return;
|
|
|
|
|
|
|
|
|
|
const rect = el.getBoundingClientRect();
|
|
|
|
|
|
|
|
|
|
if (this.isVertical) {
|
|
|
|
|
const clickRatio = (e.clientY - rect.top) / rect.height;
|
|
|
|
|
const maxScroll = this.provider.contentHeight - this.provider.viewportHeight;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
viewport.scrollTop = clickRatio * maxScroll;
|
|
|
|
|
} else {
|
|
|
|
|
const clickRatio = (e.clientX - rect.left) / rect.width;
|
|
|
|
|
const maxScroll = this.provider.contentWidth - this.provider.viewportWidth;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
viewport.scrollLeft = clickRatio * maxScroll;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ── Scroll value for ARIA ────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
private get scrollPercent(): number {
|
|
|
|
|
return Math.round(
|
|
|
|
|
(this.isVertical ? this.provider.getScrollProgressY() : this.provider.getScrollProgressX()) * 100,
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
this.assertProps({
|
|
|
|
|
...this.baseProps,
|
|
|
|
|
role: 'scrollbar' as const,
|
|
|
|
|
'aria-controls': this.provider.viewportRef.current?.id || undefined,
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
'aria-valuenow': this.scrollPercent,
|
|
|
|
|
'aria-valuemin': 0,
|
|
|
|
|
'aria-valuemax': 100,
|
|
|
|
|
'aria-orientation': this.opts.orientation.current,
|
soma: audit fixes — 84 issues across 25 components, Table complete
Table component:
- Complete state manager: sorting, filtering, pagination, selection,
column pinning (sticky), column sizing, expandable rows (sub-rows +
detail panels), column visibility
- Provider renders <table> with translated aria-label
- Sorting opt-in per column, consumer places sort buttons
- filteredRowCount/totalRowCount for correct pagination count
- Sub-row IDs hierarchical (parentId.subIndex), no collisions
- Production-grade test page (Swiss Industrial design)
- Full README with all features documented
Critical fixes (10):
- Toast: memory leaks (timer + hotkey listener cleanup via $effect)
- Toast: restartTimer() method for promise-based toasts
- ScrollArea: type='always' now works (check order fix)
- ScrollArea: thumb click no longer triggers track jump
- Tooltip: no crash without <Tooltip.Group> (ctx.getOr)
- Combobox: click-outside-to-close fixed (isValidEvent)
- Popover: stray 'n' character removed from popover.svelte
- TreeView: ARIA ownership fixed (role=treeitem on Branch, not Control)
- Splitter: documented required array spread for reactivity
High fixes (14):
- Checkbox: group disabled/name propagation + checked sync via $effect
- Select: aria-labelledby on content, aria-disabled on items
- Stepper: aria-controls + aria-labelledby cross-linking
- TagsInput: highlightPrev returns to input, role on Control/Item
- Editable: Preview role=button + aria-label
- Pagination: translated aria-label on items
- RadioGroup: removed unused Soma import
Medium fixes (60):
- registerContract() added to all 25 components
- Dead config=getSoma() removed from 7 providers
- Dead imports removed (Tooltip, Popover, Slider, Combobox)
- Dialog: aria-modal conditional on modal prop
- Slider: pointer capture release + onpointercancel
- Popover: hover timeout cleanup, aria-modal support
- Tabs: inactive content hidden + aria-hidden + tabindex=-1
- ToggleGroup: aria-orientation + roving tabindex fallback
- Toolbar: data-disabled on Button
- Stepper: Content tabindex
- TreeView: RTL keyboard support (expand/collapse key swap)
- NumberField: Enter key commit, clampOnBlur, allowMouseWheel, scrubber a11y
- Toast: data-state on root, aria-live on viewport
- ScrollArea: scrollbar aria-label + tabindex
- Collapsible: part root (not provider), aria-controls, role=region
- Tooltip: removed dead provider part from attrs
Architecture:
- COMPONENT_GUIDE.md: 14 audit-derived rules (A1-A14)
- Checklist expanded from 15 to 23 steps
- 8 new HTML primitive types (Table, THead, TBody, TFoot, TR, TH, TD, Caption)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
'aria-label': this.isVertical ? 'Vertical scrollbar' : 'Horizontal scrollbar',
|
|
|
|
|
tabindex: -1,
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
'data-state': this.shouldShow ? 'visible' : 'hidden',
|
|
|
|
|
'data-orientation': this.opts.orientation.current,
|
|
|
|
|
'data-hover': boolToEmptyStrOrUndef(this.hovering),
|
|
|
|
|
'data-dragging': boolToEmptyStrOrUndef(this.dragging),
|
|
|
|
|
'data-overflow-x': boolToEmptyStrOrUndef(this.provider.hasOverflowX),
|
|
|
|
|
'data-overflow-y': boolToEmptyStrOrUndef(this.provider.hasOverflowY),
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
onpointerenter: this.onpointerenter,
|
|
|
|
|
onpointerleave: this.onpointerleave,
|
|
|
|
|
onclick: this.onclick,
|
|
|
|
|
} as const),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Thumb ────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
interface ScrollAreaThumbOpts extends WithRefOpts {}
|
|
|
|
|
|
|
|
|
|
export class ScrollAreaThumbProvider extends Provider<ScrollAreaThumbOpts> {
|
|
|
|
|
static from(opts: ScrollAreaThumbOpts) {
|
|
|
|
|
return new ScrollAreaThumbProvider(opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly scrollbar: ScrollAreaScrollbarProvider;
|
|
|
|
|
readonly provider: ScrollAreaProvider;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
|
|
|
|
|
private dragStartY = 0;
|
|
|
|
|
private dragStartX = 0;
|
|
|
|
|
private dragStartScrollTop = 0;
|
|
|
|
|
private dragStartScrollLeft = 0;
|
|
|
|
|
|
|
|
|
|
private constructor(opts: ScrollAreaThumbOpts) {
|
|
|
|
|
super(opts, 'ScrollArea', 'thumb', attrs.thumb);
|
|
|
|
|
this.scrollbar = ScrollAreaScrollbarProvider.ctx.get();
|
|
|
|
|
this.provider = this.scrollbar.provider;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private get isVertical(): boolean {
|
|
|
|
|
return this.scrollbar.opts.orientation.current === 'vertical';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Size calculation ─────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
private get thumbSize(): number {
|
|
|
|
|
if (this.isVertical) {
|
|
|
|
|
const ratio = this.provider.viewportHeight / this.provider.contentHeight;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
const trackHeight = this.scrollbar.opts.ref.current?.clientHeight ?? 0;
|
|
|
|
|
return Math.max(ratio * trackHeight, 20);
|
|
|
|
|
} else {
|
|
|
|
|
const ratio = this.provider.viewportWidth / this.provider.contentWidth;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
const trackWidth = this.scrollbar.opts.ref.current?.clientWidth ?? 0;
|
|
|
|
|
return Math.max(ratio * trackWidth, 20);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private get thumbOffset(): number {
|
|
|
|
|
const scrollbarEl = this.scrollbar.opts.ref.current;
|
|
|
|
|
if (!scrollbarEl) return 0;
|
|
|
|
|
|
|
|
|
|
if (this.isVertical) {
|
|
|
|
|
const trackHeight = scrollbarEl.clientHeight;
|
|
|
|
|
const maxOffset = trackHeight - this.thumbSize;
|
|
|
|
|
return this.provider.getScrollProgressY() * maxOffset;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
} else {
|
|
|
|
|
const trackWidth = scrollbarEl.clientWidth;
|
|
|
|
|
const maxOffset = trackWidth - this.thumbSize;
|
|
|
|
|
return this.provider.getScrollProgressX() * maxOffset;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Drag handling ────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
readonly onpointerdown = (e: PointerEvent) => {
|
|
|
|
|
if (e.button !== 0) return;
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
|
|
const viewport = this.provider.viewportRef.current;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
if (!viewport) return;
|
|
|
|
|
|
|
|
|
|
this.scrollbar.dragging = true;
|
|
|
|
|
this.dragStartY = e.clientY;
|
|
|
|
|
this.dragStartX = e.clientX;
|
|
|
|
|
this.dragStartScrollTop = viewport.scrollTop;
|
|
|
|
|
this.dragStartScrollLeft = viewport.scrollLeft;
|
|
|
|
|
|
|
|
|
|
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
readonly onpointermove = (e: PointerEvent) => {
|
|
|
|
|
if (!this.scrollbar.dragging) return;
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
|
|
const viewport = this.provider.viewportRef.current;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
const scrollbarEl = this.scrollbar.opts.ref.current;
|
|
|
|
|
if (!viewport || !scrollbarEl) return;
|
|
|
|
|
|
|
|
|
|
if (this.isVertical) {
|
|
|
|
|
const deltaY = e.clientY - this.dragStartY;
|
|
|
|
|
const trackHeight = scrollbarEl.clientHeight;
|
|
|
|
|
const scrollRatio = deltaY / (trackHeight - this.thumbSize);
|
|
|
|
|
const maxScroll = this.provider.contentHeight - this.provider.viewportHeight;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
viewport.scrollTop = this.dragStartScrollTop + scrollRatio * maxScroll;
|
|
|
|
|
} else {
|
|
|
|
|
const deltaX = e.clientX - this.dragStartX;
|
|
|
|
|
const trackWidth = scrollbarEl.clientWidth;
|
|
|
|
|
const scrollRatio = deltaX / (trackWidth - this.thumbSize);
|
|
|
|
|
const maxScroll = this.provider.contentWidth - this.provider.viewportWidth;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
viewport.scrollLeft = this.dragStartScrollLeft + scrollRatio * maxScroll;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
readonly onpointerup = (_e: PointerEvent) => {
|
|
|
|
|
this.scrollbar.dragging = false;
|
|
|
|
|
this.scrollbar.scheduleHide();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
readonly onlostpointercapture = () => {
|
|
|
|
|
this.scrollbar.dragging = false;
|
|
|
|
|
};
|
|
|
|
|
|
soma: audit fixes — 84 issues across 25 components, Table complete
Table component:
- Complete state manager: sorting, filtering, pagination, selection,
column pinning (sticky), column sizing, expandable rows (sub-rows +
detail panels), column visibility
- Provider renders <table> with translated aria-label
- Sorting opt-in per column, consumer places sort buttons
- filteredRowCount/totalRowCount for correct pagination count
- Sub-row IDs hierarchical (parentId.subIndex), no collisions
- Production-grade test page (Swiss Industrial design)
- Full README with all features documented
Critical fixes (10):
- Toast: memory leaks (timer + hotkey listener cleanup via $effect)
- Toast: restartTimer() method for promise-based toasts
- ScrollArea: type='always' now works (check order fix)
- ScrollArea: thumb click no longer triggers track jump
- Tooltip: no crash without <Tooltip.Group> (ctx.getOr)
- Combobox: click-outside-to-close fixed (isValidEvent)
- Popover: stray 'n' character removed from popover.svelte
- TreeView: ARIA ownership fixed (role=treeitem on Branch, not Control)
- Splitter: documented required array spread for reactivity
High fixes (14):
- Checkbox: group disabled/name propagation + checked sync via $effect
- Select: aria-labelledby on content, aria-disabled on items
- Stepper: aria-controls + aria-labelledby cross-linking
- TagsInput: highlightPrev returns to input, role on Control/Item
- Editable: Preview role=button + aria-label
- Pagination: translated aria-label on items
- RadioGroup: removed unused Soma import
Medium fixes (60):
- registerContract() added to all 25 components
- Dead config=getSoma() removed from 7 providers
- Dead imports removed (Tooltip, Popover, Slider, Combobox)
- Dialog: aria-modal conditional on modal prop
- Slider: pointer capture release + onpointercancel
- Popover: hover timeout cleanup, aria-modal support
- Tabs: inactive content hidden + aria-hidden + tabindex=-1
- ToggleGroup: aria-orientation + roving tabindex fallback
- Toolbar: data-disabled on Button
- Stepper: Content tabindex
- TreeView: RTL keyboard support (expand/collapse key swap)
- NumberField: Enter key commit, clampOnBlur, allowMouseWheel, scrubber a11y
- Toast: data-state on root, aria-live on viewport
- ScrollArea: scrollbar aria-label + tabindex
- Collapsible: part root (not provider), aria-controls, role=region
- Tooltip: removed dead provider part from attrs
Architecture:
- COMPONENT_GUIDE.md: 14 audit-derived rules (A1-A14)
- Checklist expanded from 15 to 23 steps
- 8 new HTML primitive types (Table, THead, TBody, TFoot, TR, TH, TD, Caption)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
readonly onclick = (e: MouseEvent) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
};
|
|
|
|
|
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
this.assertProps({
|
|
|
|
|
...this.baseProps,
|
|
|
|
|
'data-state': this.scrollbar.shouldShow ? 'visible' : 'hidden',
|
|
|
|
|
'data-orientation': this.scrollbar.opts.orientation.current,
|
|
|
|
|
'data-hover': boolToEmptyStrOrUndef(this.scrollbar.hovering),
|
|
|
|
|
'data-dragging': boolToEmptyStrOrUndef(this.scrollbar.dragging),
|
|
|
|
|
style: {
|
|
|
|
|
position: 'absolute',
|
|
|
|
|
[this.isVertical ? 'top' : 'left']: `${this.thumbOffset}px`,
|
|
|
|
|
[this.isVertical ? 'height' : 'width']: `${this.thumbSize}px`,
|
|
|
|
|
[this.isVertical ? 'width' : 'height']: '100%',
|
|
|
|
|
'border-radius': 'inherit',
|
|
|
|
|
'--soma-scroll-area-thumb-width': `${this.isVertical ? '100%' : `${this.thumbSize}px`}`,
|
|
|
|
|
'--soma-scroll-area-thumb-height': `${this.isVertical ? `${this.thumbSize}px` : '100%'}`,
|
|
|
|
|
},
|
|
|
|
|
onpointerdown: this.onpointerdown,
|
|
|
|
|
onpointermove: this.onpointermove,
|
|
|
|
|
onpointerup: this.onpointerup,
|
|
|
|
|
onlostpointercapture: this.onlostpointercapture,
|
soma: audit fixes — 84 issues across 25 components, Table complete
Table component:
- Complete state manager: sorting, filtering, pagination, selection,
column pinning (sticky), column sizing, expandable rows (sub-rows +
detail panels), column visibility
- Provider renders <table> with translated aria-label
- Sorting opt-in per column, consumer places sort buttons
- filteredRowCount/totalRowCount for correct pagination count
- Sub-row IDs hierarchical (parentId.subIndex), no collisions
- Production-grade test page (Swiss Industrial design)
- Full README with all features documented
Critical fixes (10):
- Toast: memory leaks (timer + hotkey listener cleanup via $effect)
- Toast: restartTimer() method for promise-based toasts
- ScrollArea: type='always' now works (check order fix)
- ScrollArea: thumb click no longer triggers track jump
- Tooltip: no crash without <Tooltip.Group> (ctx.getOr)
- Combobox: click-outside-to-close fixed (isValidEvent)
- Popover: stray 'n' character removed from popover.svelte
- TreeView: ARIA ownership fixed (role=treeitem on Branch, not Control)
- Splitter: documented required array spread for reactivity
High fixes (14):
- Checkbox: group disabled/name propagation + checked sync via $effect
- Select: aria-labelledby on content, aria-disabled on items
- Stepper: aria-controls + aria-labelledby cross-linking
- TagsInput: highlightPrev returns to input, role on Control/Item
- Editable: Preview role=button + aria-label
- Pagination: translated aria-label on items
- RadioGroup: removed unused Soma import
Medium fixes (60):
- registerContract() added to all 25 components
- Dead config=getSoma() removed from 7 providers
- Dead imports removed (Tooltip, Popover, Slider, Combobox)
- Dialog: aria-modal conditional on modal prop
- Slider: pointer capture release + onpointercancel
- Popover: hover timeout cleanup, aria-modal support
- Tabs: inactive content hidden + aria-hidden + tabindex=-1
- ToggleGroup: aria-orientation + roving tabindex fallback
- Toolbar: data-disabled on Button
- Stepper: Content tabindex
- TreeView: RTL keyboard support (expand/collapse key swap)
- NumberField: Enter key commit, clampOnBlur, allowMouseWheel, scrubber a11y
- Toast: data-state on root, aria-live on viewport
- ScrollArea: scrollbar aria-label + tabindex
- Collapsible: part root (not provider), aria-controls, role=region
- Tooltip: removed dead provider part from attrs
Architecture:
- COMPONENT_GUIDE.md: 14 audit-derived rules (A1-A14)
- Checklist expanded from 15 to 23 steps
- 8 new HTML primitive types (Table, THead, TBody, TFoot, TR, TH, TD, Caption)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
onclick: this.onclick,
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
} as const),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Corner ──────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
interface ScrollAreaCornerOpts extends WithRefOpts {}
|
|
|
|
|
|
|
|
|
|
export class ScrollAreaCornerProvider extends Provider<ScrollAreaCornerOpts> {
|
|
|
|
|
static from(opts: ScrollAreaCornerOpts) {
|
|
|
|
|
return new ScrollAreaCornerProvider(opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly provider: ScrollAreaProvider;
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
|
|
|
|
|
private constructor(opts: ScrollAreaCornerOpts) {
|
|
|
|
|
super(opts, 'ScrollArea', 'corner', attrs.corner);
|
|
|
|
|
this.provider = ScrollAreaProvider.ctx.get();
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly shouldShow = $derived.by(
|
|
|
|
|
() => this.provider.hasOverflowX && this.provider.hasOverflowY,
|
soma: 10 new components, README docs for all 22, PrimitiveAnchorAttributes
New components (10):
- Tabs: roving tabindex, automatic/manual activation, onFocusChange
- ToggleGroup: single/multiple, roving tabindex, deselectable
- Toast: imperative API (createToaster), swipe-to-dismiss, hotkey, promise()
- ScrollArea: custom scrollbars, visibility modes, thumb drag, position tracking
- Splitter: resizable panels, collapsible, flex-grow sizing, double-click toggle
- Stepper: multi-step wizard, linear mode, step state, PrevTrigger/NextTrigger
- TreeView: WAI-ARIA tree pattern, expand/collapse, typeahead, * expand siblings
- Pagination: page range algorithm, siblingCount/boundaryCount, slice() utility
- Toolbar: WAI-ARIA toolbar, roving tabindex, integrated ToggleGroup, Separator
- Editable: inline edit, activation/submit modes, draft tracking, auto-resize
Documentation:
- README.md for all 22 components with anatomy, ARIA, data-*, keyboard, usage
- Comparison tables vs ark-ui, bits-ui, radix-ui for every component
Infrastructure:
- Added PrimitiveAnchorAttributes to $soma/types/html.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
);
|
|
|
|
|
|
|
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
this.assertProps({
|
|
|
|
|
...this.baseProps,
|
|
|
|
|
'data-state': this.shouldShow ? 'visible' : 'hidden',
|
|
|
|
|
style: {
|
|
|
|
|
width: 'var(--soma-scroll-area-corner-width)',
|
|
|
|
|
height: 'var(--soma-scroll-area-corner-height)',
|
|
|
|
|
},
|
|
|
|
|
} as const),
|
|
|
|
|
);
|
|
|
|
|
}
|