Packages added: - @bytelyst/referral-client — referral API client + share helpers - @bytelyst/subscription-client — subscription/plan API client + cache - @bytelyst/celebrations — milestone triggers, confetti, positive messages - @bytelyst/gentle-notifications — ND-friendly messaging, forbidden phrases - @bytelyst/accessibility — VoiceOver/TalkBack label generators - @bytelyst/quick-actions — progressive disclosure, smart defaults - @bytelyst/time-references — familiar duration references - @bytelyst/org-client — org/workspace/membership/license API client - @bytelyst/marketplace-client — listing/review/install API client All packages: pure TS, ESM, globalThis.fetch, no Node.js deps. 99 Vitest tests across 9 packages, 79/79 public methods covered. Review fixes applied: - time-references: fix module-level mutable state leak + add clearCustomReferences() - accessibility: fix parameter reassignment in formatDurationForA11y/numberToWords - subscription-client: fix flaky daysRemaining test (ms boundary race)
48 lines
1.3 KiB
TypeScript
48 lines
1.3 KiB
TypeScript
/**
|
|
* Progressive disclosure system, smart defaults, quick action definitions.
|
|
*
|
|
* Reduces cognitive load by surfacing only relevant UI sections and actions.
|
|
* Pure client-side TS — no backend dependency.
|
|
*/
|
|
|
|
import type { ProgressiveSection, QuickAction, SmartDefault } from './types.js';
|
|
|
|
export const MAX_VISIBLE_ITEMS = 3;
|
|
export const MAX_VISIBLE_LIST = 5;
|
|
|
|
export function getVisibleSections(
|
|
sections: ProgressiveSection[],
|
|
expandedIds: Set<string>
|
|
): ProgressiveSection[] {
|
|
return sections.filter(
|
|
s => s.defaultExpanded || expandedIds.has(s.id) || s.priority === 'primary'
|
|
);
|
|
}
|
|
|
|
export function getAvailableActions(
|
|
actions: QuickAction[],
|
|
context: { isActive?: boolean; isAuthenticated?: boolean }
|
|
): QuickAction[] {
|
|
return actions.filter(a => {
|
|
if (a.requiresAuth && !context.isAuthenticated) return false;
|
|
return true;
|
|
});
|
|
}
|
|
|
|
export function pickSmartDefault(candidates: SmartDefault[]): SmartDefault | null {
|
|
if (candidates.length === 0) return null;
|
|
|
|
const priority: SmartDefault['source'][] = [
|
|
'last_used',
|
|
'most_common',
|
|
'recommendation',
|
|
'system',
|
|
];
|
|
for (const source of priority) {
|
|
const match = candidates.find(c => c.source === source);
|
|
if (match) return match;
|
|
}
|
|
|
|
return candidates[0];
|
|
}
|