|
|
|
|
import { context, type ProviderOpts, type WithRefOpts } from '../../provider';
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
import {
|
|
|
|
|
readableActive,
|
|
|
|
|
state,
|
|
|
|
|
type Active,
|
|
|
|
|
type ActiveProps,
|
|
|
|
|
type StateProps
|
remove backward-compat re-export shims
Per architectural feedback: when relocating code to its correct layer,
do the migration completely — update every consumer directly and
delete the original. No re-export barrels at the old paths.
Removed shims:
- `src/uix/soma/attrs/` — was re-exporting `createAttrs` /
`registerContract` / `assertContract` / `getContract` from
`$uix/morfo` and the bool/data-attr formatters from `$libs/dom`.
All 66 importing files updated to import from the canonical
locations directly.
- `src/uix/soma/reactive/` — `reactive.svelte.ts` was a thin
re-export of `$libs/reactive`. The 79 consumers (every soma
provider + layers + types) now import primitives directly from
`$libs/reactive`. The `opts.ts` Props↔Opts bridge moved to
`src/uix/soma/provider/opts.ts` (its natural home — provider
plumbing, not reactive primitives).
- `attachRef` / `RefAttachment` re-export from
`src/uix/soma/provider/provider.svelte.ts` and from
`src/uix/soma/index.ts`. Both removed. Consumers
(`floating.svelte.ts`, `date-field-provider.svelte.ts`) now
import directly from `$libs/reactive`.
Also:
- Moved `ActiveProps<T>` / `StateProps<T>` types to
`src/libs/reactive/types.ts` — they're trivial generic helpers
over `Active<T>` / `State<T>` and shouldn't have lived in soma.
- Stripped soma's root barrel (`src/uix/soma/index.ts`) of every
re-export of libs/morfo concerns. It now only re-exports
actually-soma surfaces (Provider base, mergeProps, css helpers,
id, types, Soma class).
Result:
- `grep -r '\$soma' src/uix/morfo` → 0 matches
- `grep -r '\$uix' src/libs` → 0 matches
- `src/uix/soma/attrs/` and `src/uix/soma/reactive/` no longer exist
- Every import statement now reflects the real architectural layer
Verified: vitest 19/20 files / 214 tests (1 pre-existing air dead-
branch fail using `bun:test`), smoke 68/68, morfo-check 66/66.
5 months ago
|
|
|
} from '$libs/reactive';
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
import type {
|
|
|
|
|
OnChangeFn,
|
|
|
|
|
SomaKeyboardEvent,
|
|
|
|
|
Direction,
|
|
|
|
|
Arrayable,
|
|
|
|
|
StyleProperties
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
} from '../../types';
|
|
|
|
|
import { KEYS } from '../../keyboard';
|
|
|
|
|
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
import { Presence } from '../../layers/presence.svelte';
|
|
|
|
|
import { Dismissal, type DismissalBehavior } from '../../layers/dismissal.svelte';
|
|
|
|
|
import { SafePolygon } from '../../layers/floating/safe-polygon';
|
|
|
|
|
import {
|
|
|
|
|
FloatingProvider,
|
|
|
|
|
FloatingContent,
|
|
|
|
|
FloatingArrow,
|
|
|
|
|
FloatingAnchor,
|
|
|
|
|
type Side,
|
|
|
|
|
type Align,
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
type Boundary
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
} from '../../layers/floating';
|
|
|
|
|
|
morfo: port 65 components + sium.lazy + morfo-check passes 66/66
All 65 soma components now consume their morfo as the cross-layer contract.
createAttrs(morfo) and registerContract(morfo) overloads removed — the
Morfo form is now mandatory. Each component provider has a 3-line morfo
import + wire-up block instead of 20+ lines of inline declarations.
Additions:
sium/core/lazy.ts — lazy() combinator for recursive schemas (unblocks
morfo's eventual lazy part-tree validation; tests included).
sium/examples/ — booking, color, login, settings, signup, survey, tree
form demos.
Route demos at src/routes/test/sium/{booking,color,login,settings,
signup,survey,tree}.
Tooling:
morfo-check.ts — now tolerates sibling parts sharing a physical element
(Link variant of Item, etc.). Queries via allPartAttrs cross-scope.
morfo-vocabulary-check.ts — 28 WARN (legitimate per-component
vocabularies or subsets like switch missing "indeterminate"). All
reviewed, none are bugs.
Fixes caught by morfo-check:
table: data-sorted / data-pinned marked severity:'optional' (only
emitted when sorting/pinning active, not always).
tree-grid: data-expanded on Row severity:'optional' (branches only).
menubar: data-menubar-value declared on Trigger.
splitter: data-splitter-panel-id declared on Panel.
Verify:
npm run check — 0 morfo errors (4 pre-existing in sium/examples,
unrelated).
npx vitest run src/uix/morfo — 7/7 tests pass.
npm run smoke — 65/65 routes pass.
npm run morfo:check — 66/66 morfos validate against real DOM.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
import { tooltipMorfo } from '../../../morfo/components/tooltip';
|
|
|
|
|
import { Soma } from '../../core/soma.svelte';
|
|
|
|
|
import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte';
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
export type TooltipState = 'closed' | 'delayed-open' | 'instant-open';
|
|
|
|
|
|
|
|
|
|
// ── Group Provider (coordinates skip-delay between sibling tooltips) ─────────
|
|
|
|
|
|
|
|
|
|
interface TooltipGroupOpts {
|
|
|
|
|
delayDuration: Active<number>;
|
|
|
|
|
skipDelayDuration: Active<number>;
|
|
|
|
|
disableHoverableContent: Active<boolean>;
|
|
|
|
|
disabled: Active<boolean>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class TooltipGroupProvider {
|
|
|
|
|
static readonly ctx = context<TooltipGroupProvider>('TooltipGroup');
|
|
|
|
|
static get(): TooltipGroupProvider | undefined {
|
|
|
|
|
return this.ctx.getOr(undefined) as TooltipGroupProvider | undefined;
|
|
|
|
|
}
|
|
|
|
|
static require(): TooltipGroupProvider {
|
|
|
|
|
return this.ctx.get();
|
|
|
|
|
}
|
|
|
|
|
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
static create(opts: TooltipGroupOpts) {
|
|
|
|
|
return TooltipGroupProvider.ctx.set(new TooltipGroupProvider(opts));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly opts: TooltipGroupOpts;
|
|
|
|
|
|
|
|
|
|
/** Timestamp of last tooltip close — used for skip-delay. */
|
|
|
|
|
lastCloseTime = 0;
|
|
|
|
|
|
|
|
|
|
private constructor(opts: TooltipGroupOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Returns true if we're within the skip-delay window (instant open). */
|
|
|
|
|
isWithinSkipDelay(): boolean {
|
|
|
|
|
return Date.now() - this.lastCloseTime < this.opts.skipDelayDuration.current;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
markClosed() {
|
|
|
|
|
this.lastCloseTime = Date.now();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Root (per-tooltip instance) ──────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
interface TooltipOpts
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
extends
|
|
|
|
|
ProviderOpts,
|
|
|
|
|
StateProps<{ open: boolean }>,
|
|
|
|
|
ActiveProps<{
|
|
|
|
|
delayDuration: number | undefined;
|
|
|
|
|
closeDelay: number;
|
|
|
|
|
disableHoverableContent: boolean | undefined;
|
|
|
|
|
disabled: boolean | undefined;
|
|
|
|
|
onOpenChangeComplete: OnChangeFn<boolean>;
|
|
|
|
|
}> {}
|
|
|
|
|
|
|
|
|
|
export class TooltipProvider {
|
|
|
|
|
readonly opts: TooltipOpts;
|
|
|
|
|
readonly runtimePart: SomaRuntimePart;
|
|
|
|
|
readonly soma: Soma;
|
|
|
|
|
readonly runtime: SomaRuntime;
|
|
|
|
|
static readonly ctx = context<TooltipProvider>('Tooltip');
|
|
|
|
|
static get(): TooltipProvider | undefined {
|
|
|
|
|
return this.ctx.getOr(undefined) as TooltipProvider | undefined;
|
|
|
|
|
}
|
|
|
|
|
static require(): TooltipProvider {
|
|
|
|
|
return this.ctx.get();
|
|
|
|
|
}
|
|
|
|
|
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
static create(opts: TooltipOpts) {
|
|
|
|
|
return new TooltipProvider(opts);
|
|
|
|
|
}
|
|
|
|
|
|
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 group: TooltipGroupProvider | undefined;
|
|
|
|
|
readonly floatingProvider: FloatingProvider;
|
|
|
|
|
readonly contentPresence: Presence;
|
|
|
|
|
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
private internalTooltipState = $state<TooltipState>('closed');
|
|
|
|
|
private openTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
|
private closeTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
|
private contentRef = state<HTMLElement | null>(null);
|
|
|
|
|
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
/**
|
|
|
|
|
* Reactive tooltip state that syncs with the `open` prop.
|
|
|
|
|
* When `open` is set programmatically (not via hover/focus), data-state updates accordingly.
|
|
|
|
|
*/
|
|
|
|
|
get tooltipState(): TooltipState {
|
|
|
|
|
// If open is true but internal state is closed, it was set programmatically
|
|
|
|
|
if (this.opts.open.current && this.internalTooltipState === 'closed') {
|
|
|
|
|
return 'instant-open';
|
|
|
|
|
}
|
|
|
|
|
// If open is false, always report closed
|
|
|
|
|
if (!this.opts.open.current) {
|
|
|
|
|
return 'closed';
|
|
|
|
|
}
|
|
|
|
|
return this.internalTooltipState;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// tracked IDs and refs
|
|
|
|
|
contentId = state('');
|
|
|
|
|
triggerId = state('');
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
triggerRef = state<HTMLElement | null>(null);
|
|
|
|
|
|
|
|
|
|
private constructor(opts: TooltipOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.soma = Soma.require();
|
|
|
|
|
this.runtime = this.soma.runtime(tooltipMorfo, {});
|
|
|
|
|
this.runtimePart = this.runtime.part('provider', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
context: TooltipProvider.ctx
|
|
|
|
|
});
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
this.group = TooltipGroupProvider.get();
|
|
|
|
|
this.floatingProvider = FloatingProvider.create();
|
|
|
|
|
|
|
|
|
|
this.contentPresence = new Presence({
|
|
|
|
|
open: opts.open,
|
|
|
|
|
ref: this.contentRef,
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
onComplete: (open) => opts.onOpenChangeComplete.current(open)
|
|
|
|
|
});
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
|
|
|
|
|
// SafePolygon: prevents tooltip from closing when pointer traverses
|
|
|
|
|
// the gap between trigger and content (hoverable tooltips)
|
|
|
|
|
new SafePolygon({
|
|
|
|
|
enabled: () => opts.open.current && !this.hoverableDisabled,
|
|
|
|
|
triggerNode: () => this.triggerRef.current,
|
|
|
|
|
contentNode: () => this.contentRef.current,
|
|
|
|
|
onPointerExit: () => this.handleClose(),
|
|
|
|
|
buffer: 2,
|
|
|
|
|
transitIntentTimeout: 200
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Effective delay (per-tooltip override → group default). */
|
|
|
|
|
get delay(): number {
|
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
|
|
|
return this.opts.delayDuration.current ?? this.group?.opts.delayDuration.current ?? 700;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Effective disabled state. */
|
|
|
|
|
get isDisabled(): boolean {
|
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
|
|
|
return (this.opts.disabled.current ?? this.group?.opts.disabled.current) || false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Effective disableHoverableContent. */
|
|
|
|
|
get hoverableDisabled(): boolean {
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
return (
|
|
|
|
|
(this.opts.disableHoverableContent.current ??
|
|
|
|
|
this.group?.opts.disableHoverableContent.current) ||
|
|
|
|
|
false
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleOpen(instant = false) {
|
|
|
|
|
if (this.isDisabled) return;
|
|
|
|
|
this.clearTimeouts();
|
|
|
|
|
|
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 (instant || this.group?.isWithinSkipDelay()) {
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
this.internalTooltipState = 'instant-open';
|
|
|
|
|
this.opts.open.current = true;
|
|
|
|
|
} else {
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
this.internalTooltipState = 'delayed-open';
|
|
|
|
|
this.openTimeout = setTimeout(() => {
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
this.internalTooltipState = 'instant-open';
|
|
|
|
|
this.opts.open.current = true;
|
|
|
|
|
}, this.delay);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleClose() {
|
|
|
|
|
this.clearTimeouts();
|
|
|
|
|
const closeDelay = this.opts.closeDelay.current;
|
|
|
|
|
|
|
|
|
|
if (closeDelay > 0) {
|
|
|
|
|
this.closeTimeout = setTimeout(() => {
|
|
|
|
|
this.doClose();
|
|
|
|
|
}, closeDelay);
|
|
|
|
|
} else {
|
|
|
|
|
this.doClose();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private doClose() {
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
this.internalTooltipState = 'closed';
|
|
|
|
|
this.opts.open.current = 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
|
|
|
this.group?.markClosed();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Cancel pending close (when pointer enters content). */
|
|
|
|
|
cancelClose() {
|
|
|
|
|
if (this.closeTimeout !== null) {
|
|
|
|
|
clearTimeout(this.closeTimeout);
|
|
|
|
|
this.closeTimeout = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private clearTimeouts() {
|
|
|
|
|
if (this.openTimeout !== null) {
|
|
|
|
|
clearTimeout(this.openTimeout);
|
|
|
|
|
this.openTimeout = null;
|
|
|
|
|
}
|
|
|
|
|
if (this.closeTimeout !== null) {
|
|
|
|
|
clearTimeout(this.closeTimeout);
|
|
|
|
|
this.closeTimeout = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setContentRef(el: HTMLElement | null) {
|
|
|
|
|
this.contentRef.current = el;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Trigger ──────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
interface TooltipTriggerOpts extends WithRefOpts {}
|
|
|
|
|
|
|
|
|
|
export class TooltipTriggerProvider {
|
|
|
|
|
readonly opts: TooltipTriggerOpts;
|
|
|
|
|
readonly runtimePart: SomaRuntimePart;
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
static create(opts: TooltipTriggerOpts) {
|
|
|
|
|
return new TooltipTriggerProvider(opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly provider: TooltipProvider;
|
|
|
|
|
|
|
|
|
|
private constructor(opts: TooltipTriggerOpts) {
|
soma/morfo: typed createAttrs + 6 audit batches + form hang fix + A36
## morfo: typed createAttrs
- `types.ts`: all array fields are now `readonly` so morfos can be authored
with `as const satisfies Morfo` without casts.
- `createAttrs` is a generic `<const M extends MorfoShape>` that infers the
emitted attr map from the morfo's literal shape. Typos like `attrs.trigerr`
are now compile errors; autocomplete lists every valid part.
- All 66 morfos migrated: `export const xMorfo = { ... } as const satisfies Morfo`.
- Two latent bugs the new typing caught: `dateRangeFieldAttrs.root` and
`timeRangeFieldAttrs.root` — legacy from the root→provider refactor, fixed
to `.provider`.
- Docs (morfo/README, COMPONENT_GUIDE) mandate `as const satisfies Morfo`;
the older `: Morfo` annotation widens literals and loses autocomplete.
## Audit batches 1–7 (soma-audit-2026-04-20)
Batch 1 — Keyboard a11y (A14/A12):
- Tabs: `isFallbackTabStop(el)` using `untrack` → first trigger gets
`tabindex=0` when no tab matches (WCAG 2.1.1 was failing).
- RatingGroup: `dir` prop + `getDirectionalKeys(dir, 'horizontal')` for RTL.
- Accordion P1-1/P1-6 dismissed: roving/labelledby already correct per APG.
Batch 2 — A33 reactive collections: Select `labelRegistry` and NavigationMenu
`triggerRefs` migrated to `SvelteMap`.
Batch 3 — A31 O(N²) fix: RadioGroup lifts `hasSelection` + `isFallbackTabStop`
to the provider with `untrack`-wrapped DOM walk. Per-item derivations drop
from O(N²) to O(1) per trigger.
Batch 4 — Morfo aria sync: toast / time-field / date-field / tabs /
tag-group / navigation-menu declare every aria the provider emits
(14 entries across 6 files).
Batch 5 — Accessible naming props: Tabs.List, ToggleGroup, TreeView,
NavigationMenu expose `aria-label?` / `aria-labelledby?` with explicit
"required unless labelledby is set" JSDoc.
Batch 6 — A30 cleanup: Checkbox `setLabelId` and 5 trigger-ref providers
(select/tooltip/link-preview/dropdown-menu/context-menu) migrated from
`$effect(() => parent.ref = opts.ref)` to the `Provider` base's
`onRefChange` callback (fires via attachRef inside `untrack`).
Batch 7 — A11 wrapper thinning: stepper/tree-view wrappers removed
`ctx.get()`, providers expose proxy derivations; time/date-range-field
inputs use `untrack(() => …)` for one-shot id registration; menubar
content's 40-line keyboard nav moved to `MenubarMenuProvider.onContentKeydown`;
color-picker area + channel-slider pointer state machines moved to the
providers with `onpointerdown/move/up` emitted via `props`.
form-auto-fields deferred with justification (reflective schema renderer,
not a state-holding wrapper).
## Form hang fix (A36)
`runValidate` entered the `isPromiseLike` branch even for sync schemas
because sium's Standard-Schema adapter declares `validate: async`. The
fallback `return { errors, issues }` read both reactive vars inside the
validation `$effect` while the `.then(...)` microtask wrote them
→ microtask-mediated loop, silent to Svelte's sync effect-depth guard.
Symptom: kitchen-sink hung the tab on mount with onChange / onBlur.
Fix: `return untrack(() => ({ errors, issues }))`. Regression locked by
two new 5s-timeout tests in `form-auto-fields.svelte.test.ts`.
Pattern codified as A36 in COMPONENT_GUIDE; CLAUDE.md count updated to
A1–A36 / 39 items.
## Verification
- `npm run check`: 0 errors in soma/morfo scope (sema demo pre-existing
errors untouched).
- `npx vitest run src/uix/soma src/uix/morfo`: all tests green
(94 + 7 = 101 tests, inc. 2 new form regression tests).
- `npm run smoke`: 65/65 routes.
- `npx tsx scripts/morfo-check.ts`: 66/66 morfos.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
// A30: mirror trigger element to provider via `onRefChange`.
|
|
|
|
|
this.opts = opts;
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
this.provider = TooltipProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('trigger', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
states: {
|
|
|
|
|
'instant-open': () => this.provider.tooltipState
|
|
|
|
|
},
|
|
|
|
|
parts: {
|
|
|
|
|
content: () =>
|
|
|
|
|
this.provider.opts.open.current ? this.provider.contentId.current || undefined : undefined
|
|
|
|
|
},
|
|
|
|
|
owner: this,
|
|
|
|
|
onRefChange: (el) => {
|
|
|
|
|
this.provider.triggerRef.current = el;
|
|
|
|
|
},
|
|
|
|
|
syncAttrs: true
|
|
|
|
|
});
|
|
|
|
|
this.provider.triggerId.current = opts.id.current;
|
|
|
|
|
|
|
|
|
|
FloatingAnchor.create({
|
|
|
|
|
id: opts.id,
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
ref: readableActive(() => opts.ref.current)
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly onpointerenter = () => {
|
|
|
|
|
this.provider.handleOpen();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
readonly onpointerleave = () => {
|
|
|
|
|
this.provider.handleClose();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
readonly onfocus = () => {
|
|
|
|
|
this.provider.handleOpen(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
readonly onblur = () => {
|
|
|
|
|
this.provider.handleClose();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
this.runtimePart.assert({
|
|
|
|
|
...this.runtimePart.props,
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
tabindex: 0,
|
|
|
|
|
onpointerenter: this.onpointerenter,
|
|
|
|
|
onpointerleave: this.onpointerleave,
|
|
|
|
|
onfocus: this.onfocus,
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
onblur: this.onblur
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
} as const)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Content ──────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
interface TooltipContentOpts
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
extends
|
|
|
|
|
WithRefOpts,
|
|
|
|
|
ActiveProps<{
|
|
|
|
|
side: Side;
|
|
|
|
|
sideOffset: number;
|
|
|
|
|
align: Align;
|
|
|
|
|
alignOffset: number;
|
|
|
|
|
arrowPadding: number;
|
|
|
|
|
avoidCollisions: boolean;
|
|
|
|
|
collisionBoundary: Arrayable<Boundary>;
|
|
|
|
|
collisionPadding: number | Partial<Record<Side, number>>;
|
|
|
|
|
sticky: 'partial' | 'always';
|
|
|
|
|
hideWhenDetached: boolean;
|
|
|
|
|
updatePositionStrategy: 'optimized' | 'always';
|
|
|
|
|
strategy: 'fixed' | 'absolute';
|
|
|
|
|
dir: Direction;
|
|
|
|
|
style: StyleProperties | null | undefined | string;
|
|
|
|
|
ariaLabel: string | undefined;
|
|
|
|
|
onEscapeKeydown: (e: KeyboardEvent) => void;
|
|
|
|
|
escapeKeydownBehavior: DismissalBehavior;
|
|
|
|
|
}> {}
|
|
|
|
|
|
|
|
|
|
export class TooltipContentProvider {
|
|
|
|
|
readonly opts: TooltipContentOpts;
|
|
|
|
|
readonly runtimePart: SomaRuntimePart;
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
static create(opts: TooltipContentOpts) {
|
|
|
|
|
return new TooltipContentProvider(opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly provider: TooltipProvider;
|
|
|
|
|
readonly floating: FloatingContent;
|
|
|
|
|
readonly dismissal: Dismissal;
|
|
|
|
|
|
|
|
|
|
private constructor(opts: TooltipContentOpts) {
|
|
|
|
|
this.opts = opts;
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
this.provider = TooltipProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('content', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
states: {
|
|
|
|
|
'instant-open': () => this.provider.tooltipState
|
|
|
|
|
},
|
|
|
|
|
props: {
|
|
|
|
|
ariaLabel: () => this.opts.ariaLabel.current
|
|
|
|
|
},
|
|
|
|
|
owner: this,
|
|
|
|
|
onRefChange: (el) => {
|
|
|
|
|
this.provider.setContentRef(el);
|
|
|
|
|
},
|
|
|
|
|
syncAttrs: true
|
|
|
|
|
});
|
|
|
|
|
this.provider.contentId.current = opts.id.current;
|
|
|
|
|
|
|
|
|
|
// Floating
|
|
|
|
|
this.floating = FloatingContent.create({
|
|
|
|
|
id: opts.id,
|
|
|
|
|
wrapperId: readableActive(() => `${opts.id.current}-wrapper`),
|
|
|
|
|
side: opts.side,
|
|
|
|
|
sideOffset: opts.sideOffset,
|
|
|
|
|
align: opts.align,
|
|
|
|
|
alignOffset: opts.alignOffset,
|
|
|
|
|
arrowPadding: opts.arrowPadding,
|
|
|
|
|
avoidCollisions: opts.avoidCollisions,
|
|
|
|
|
collisionBoundary: opts.collisionBoundary,
|
|
|
|
|
collisionPadding: opts.collisionPadding,
|
|
|
|
|
sticky: opts.sticky,
|
|
|
|
|
hideWhenDetached: opts.hideWhenDetached,
|
|
|
|
|
updatePositionStrategy: opts.updatePositionStrategy,
|
|
|
|
|
strategy: opts.strategy,
|
|
|
|
|
onPlaced: readableActive(() => () => {}),
|
|
|
|
|
dir: opts.dir,
|
|
|
|
|
style: opts.style,
|
|
|
|
|
enabled: readableActive(() => this.provider.opts.open.current),
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
customAnchor: readableActive(() => null)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Dismissal (escape only, no interact-outside for tooltip)
|
|
|
|
|
this.dismissal = Dismissal.use({
|
|
|
|
|
ref: readableActive(() => opts.ref.current),
|
|
|
|
|
enabled: readableActive(() => this.provider.opts.open.current),
|
|
|
|
|
onEscapeKeydown: readableActive(() => (e: KeyboardEvent) => {
|
|
|
|
|
opts.onEscapeKeydown.current(e);
|
|
|
|
|
if (!e.defaultPrevented) this.provider.handleClose();
|
|
|
|
|
}),
|
|
|
|
|
escapeKeydownBehavior: opts.escapeKeydownBehavior,
|
|
|
|
|
onInteractOutside: readableActive(() => () => {}),
|
|
|
|
|
interactOutsideBehavior: readableActive(() => 'ignore' as const),
|
|
|
|
|
onFocusOutside: readableActive(() => () => {}),
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
isValidEvent: readableActive(() => () => false)
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly isPresent = $derived.by(() => this.provider.contentPresence.isPresent);
|
|
|
|
|
|
|
|
|
|
readonly wrapperProps = $derived.by(() => ({
|
|
|
|
|
...this.floating.wrapperProps,
|
|
|
|
|
style: {
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
...(typeof this.floating.wrapperProps.style === 'object'
|
|
|
|
|
? this.floating.wrapperProps.style
|
|
|
|
|
: {}),
|
|
|
|
|
'pointer-events': this.provider.hoverableDisabled ? 'none' : 'auto'
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
readonly onpointerenter = () => {
|
|
|
|
|
if (!this.provider.hoverableDisabled) {
|
|
|
|
|
this.provider.cancelClose();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
readonly onpointerleave = () => {
|
|
|
|
|
this.provider.handleClose();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
this.runtimePart.assert({
|
|
|
|
|
...this.runtimePart.props,
|
|
|
|
|
...this.floating.props,
|
|
|
|
|
...this.provider.contentPresence.transitionAttrs,
|
|
|
|
|
...this.dismissal.props,
|
|
|
|
|
onpointerenter: this.onpointerenter,
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
onpointerleave: this.onpointerleave
|
|
|
|
|
} as const)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Arrow ────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
interface TooltipArrowOpts extends WithRefOpts {}
|
|
|
|
|
|
|
|
|
|
export class TooltipArrowProvider {
|
|
|
|
|
readonly opts: TooltipArrowOpts;
|
|
|
|
|
readonly runtimePart: SomaRuntimePart;
|
|
|
|
|
readonly provider: TooltipProvider;
|
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
|
|
|
static create(opts: TooltipArrowOpts) {
|
|
|
|
|
return new TooltipArrowProvider(opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly floatingArrow: FloatingArrow;
|
|
|
|
|
|
|
|
|
|
private constructor(opts: TooltipArrowOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.provider = TooltipProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('arrow', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
this.floatingArrow = FloatingArrow.create(opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
this.runtimePart.assert({
|
|
|
|
|
...this.runtimePart.props,
|
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation)
- Add createSvelteLang() with reactivity for locale and schema changes
- Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t()
- Add reactive dir resolution in all component wrappers
- Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.)
- Fix slider RTL: range, thumb, tick use right/left based on dir
- Add table structural parts: Header, Body, Footer wrappers
- Implement ColumnPinning, ColumnSizing, Expanded in table-core
- Remove soma core formatters, translator.svelte, prop-resolvers (moved to App)
- Remove duplicate convenience getters (locale, dir, translate) from App/Soma
- Audit all 26 soma components, create audit docs with 84 issues found
- Update test page with pinning, sizing, expandable rows demos
6 months ago
|
|
|
...this.floatingArrow.props
|
|
|
|
|
} as const)
|
|
|
|
|
);
|
|
|
|
|
}
|