Skip to content

refactor(bundle-size): convert Subscribable family to factories#542

Open
layershifter wants to merge 5 commits into
microsoft:masterfrom
layershifter:chore/bundle-size-stack-5
Open

refactor(bundle-size): convert Subscribable family to factories#542
layershifter wants to merge 5 commits into
microsoft:masterfrom
layershifter:chore/bundle-size-stack-5

Conversation

@layershifter
Copy link
Copy Markdown
Member

Summary

Converts the Subscribable<A, B> base class and its five subclasses (KeyboardNavigationState, FocusedElementState, ObservedElementAPI, two CrossOrigin-internal subscribables) from class to factory functions returning plain objects.

Also trims Subscribable itself: drops the emit codepath for deprecated event names that no internal callers use.

Same pattern as the API-class conversions in the following PR: private fields become closure-captured locals, arrow-bound methods become local const arrows, the public interface in Types.ts is unchanged.

Stack context

Stacked on top of #541. Net new in this PR: the Subscribable family conversion + emit trim.

layershifter and others added 5 commits May 11, 2026 11:41
\`patch-package\` postinstall hook applies three changes to
keyborg@2.14.0 covering both the ESM (\`dist/index.js\`) and CJS
(\`dist/index.cjs\`) bundles:

1. \`event.details = details\` — drop the \`@deprecated\` alias of
   \`event.detail\`. Tabster reads \`e.detail\` exclusively (verified
   across src/State/FocusedElement.ts and the rest of the codebase).

2. \`triggerKeys\` / \`dismissKeys\` props + the supporting
   \`shouldDismiss\` / \`scheduleDismiss\` / \`dismissTimer\`
   machinery. Tabster only ever calls \`createKeyborg(getWindow())\`
   with no props.

3. \`canOverrideNativeFocus\` runtime probe. Replaces the
   \`_canOverrideNativeFocus\` flag with the implicit-true assumption
   modern browsers (everything since IE9) already satisfy. The
   conditional \`details.isFocusedProgrammatically\` write becomes
   unconditional — semantically identical when override works.

Bundle deltas (createTabster default-mode):
  keyborg slice: 3.71 → 3.12 kB (-590 B, -16%)
  createTabster:  30.78 → 30.18 kB (-600 B)
  getModalizer:   38.47 → 37.87 kB (-600 B)
  getMover:       44.54 → 43.94 kB (-600 B)
  getCrossOrigin: 89.64 → 89.04 kB (-600 B)
  allExports:     92.09 → 91.50 kB (-590 B)

Tests pass: 3 pre-existing failures, no regressions across default,
uncontrolled, and root-dummy-inputs modes.

Stop-gap until upstream microsoft/keyborg can release the same
trims (the changes belong there, not as a Tabster-side fork).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Converts the `Subscribable<A, B>` abstract class and its consumers to
factory functions returning plain objects.

- `Subscribable` → `createSubscribable<A,B>()` factory returning a
  `SubscribableCore` interface. The public surface (subscribe/
  subscribeFirst/unsubscribe) matches `Types.Subscribable`; setVal/
  getVal/trigger are exposed for the composing factory only.
- `KeyboardNavigationState` class → `createKeyboardNavigationState`
  factory.
- `FocusedElementState` class → `createFocusedElementState` factory.
  `FocusedElementState` is preserved as a const namespace for the
  `forgetMemorized` and `findNextTabbable` static helpers.
- `ObservedElementAPI` class → `createObservedElementAPI` factory.
- `CrossOriginFocusedElementState` class →
  `createCrossOriginFocusedElementState` factory, with `setVal` static
  kept under same-named const namespace.
- `CrossOriginObservedElementState` class →
  `createCrossOriginObservedElementState` factory, with `trigger` static
  kept under same-named const namespace.

Also trims `Subscribable` itself: drops the `callCallbacks` helper in
favour of the inlined `trigger` closure, and adds `declare` to
`TabsterCustomEvent.details` to drop the redundant initializer SWC was
emitting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
tabster
all exports
113.84 kB
30.937 kB
107.714 kB
30.209 kB
-6.126 kB
-728 B
tabster
createTabster (core)
39.761 kB
11.892 kB
37.029 kB
11.481 kB
-2.732 kB
-411 B
tabster
focusable.findAll
0 B
0 B
37.052 kB
11.487 kB
🆕 New entry
tabster
focusable.findLast
0 B
0 B
37.053 kB
11.489 kB
🆕 New entry
tabster
focusable.findNext
0 B
0 B
37.053 kB
11.489 kB
🆕 New entry
tabster
focusable.findPrev
0 B
0 B
37.053 kB
11.489 kB
🆕 New entry
tabster
getCrossOrigin
110.623 kB
30.244 kB
104.62 kB
29.417 kB
-6.003 kB
-827 B
tabster
getDeloser
49.268 kB
14.234 kB
46.386 kB
13.83 kB
-2.882 kB
-404 B
tabster
getGroupper
47 kB
13.593 kB
44.114 kB
13.209 kB
-2.886 kB
-384 B
tabster
getModalizer
49.072 kB
14.378 kB
46.242 kB
13.973 kB
-2.83 kB
-405 B
tabster
getMover
54.653 kB
15.887 kB
51.616 kB
15.477 kB
-3.037 kB
-410 B
tabster
getObservedElement
45.564 kB
13.484 kB
41.701 kB
12.988 kB
-3.863 kB
-496 B
tabster
getOutline
48.867 kB
14.216 kB
45.265 kB
13.699 kB
-3.602 kB
-517 B
tabster
getRestorer
42.518 kB
12.52 kB
39.642 kB
12.116 kB
-2.876 kB
-404 B

🤖 This report was generated against a579ebbd50e37f1565551549fe57bbc9ddafab64

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant