@sc4rfurryx/proteusjs 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +684 -899
- package/dist/.tsbuildinfo +1 -1
- package/dist/modules/a11y-audit.d.ts +2 -10
- package/dist/modules/a11y-audit.esm.js +31 -476
- package/dist/modules/a11y-audit.esm.js.map +1 -1
- package/dist/modules/a11y-primitives.d.ts +9 -42
- package/dist/modules/a11y-primitives.esm.js +70 -401
- package/dist/modules/a11y-primitives.esm.js.map +1 -1
- package/dist/modules/anchor.d.ts +2 -1
- package/dist/modules/anchor.esm.js +3 -2
- package/dist/modules/anchor.esm.js.map +1 -1
- package/dist/modules/container.d.ts +1 -1
- package/dist/modules/container.esm.js +34 -34
- package/dist/modules/container.esm.js.map +1 -1
- package/dist/modules/perf.d.ts +1 -1
- package/dist/modules/perf.esm.js +2 -2
- package/dist/modules/popover.d.ts +1 -1
- package/dist/modules/popover.esm.js +2 -2
- package/dist/modules/scroll.d.ts +1 -1
- package/dist/modules/scroll.esm.js +14 -14
- package/dist/modules/scroll.esm.js.map +1 -1
- package/dist/modules/transitions.d.ts +1 -1
- package/dist/modules/transitions.esm.js +12 -12
- package/dist/modules/transitions.esm.js.map +1 -1
- package/dist/modules/typography.d.ts +1 -1
- package/dist/modules/typography.esm.js +2 -2
- package/dist/proteus.cjs.js +163 -941
- package/dist/proteus.cjs.js.map +1 -1
- package/dist/proteus.d.ts +23 -68
- package/dist/proteus.esm.js +163 -941
- package/dist/proteus.esm.js.map +1 -1
- package/dist/proteus.esm.min.js +2 -2
- package/dist/proteus.esm.min.js.map +1 -1
- package/dist/proteus.js +163 -941
- package/dist/proteus.js.map +1 -1
- package/dist/proteus.min.js +2 -2
- package/dist/proteus.min.js.map +1 -1
- package/package.json +44 -7
- package/src/adapters/react.ts +607 -264
- package/src/adapters/svelte.ts +321 -321
- package/src/adapters/vue.ts +268 -268
- package/src/core/ProteusJS.ts +6 -6
- package/src/index.ts +3 -3
- package/src/modules/a11y-audit/index.ts +84 -608
- package/src/modules/a11y-primitives/index.ts +152 -554
- package/src/modules/anchor/index.ts +259 -257
- package/src/modules/container/index.ts +230 -230
- package/src/modules/perf/index.ts +291 -291
- package/src/modules/popover/index.ts +238 -238
- package/src/modules/scroll/index.ts +251 -251
- package/src/modules/transitions/index.ts +145 -145
- package/src/modules/typography/index.ts +239 -239
- package/src/utils/version.ts +1 -1
- package/dist/adapters/react.d.ts +0 -139
- package/dist/adapters/react.esm.js +0 -848
- package/dist/adapters/react.esm.js.map +0 -1
- package/dist/adapters/svelte.d.ts +0 -181
- package/dist/adapters/svelte.esm.js +0 -908
- package/dist/adapters/svelte.esm.js.map +0 -1
- package/dist/adapters/vue.d.ts +0 -205
- package/dist/adapters/vue.esm.js +0 -872
- package/dist/adapters/vue.esm.js.map +0 -1
package/dist/proteus.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* ProteusJS
|
|
2
|
+
* ProteusJS v2.0.0
|
|
3
3
|
* Shape-shifting responsive design that adapts like the sea god himself
|
|
4
4
|
* (c) 2025 sc4rfurry
|
|
5
5
|
* Released under the MIT License
|
|
@@ -15225,7 +15225,7 @@ function checkPassiveEventListenerSupport() {
|
|
|
15225
15225
|
/**
|
|
15226
15226
|
* Version utilities for ProteusJS
|
|
15227
15227
|
*/
|
|
15228
|
-
const version = '
|
|
15228
|
+
const version = '2.0.0';
|
|
15229
15229
|
|
|
15230
15230
|
/**
|
|
15231
15231
|
* ProteusJS - Main library class
|
|
@@ -15992,7 +15992,7 @@ ProteusJS.instance = null;
|
|
|
15992
15992
|
* @sc4rfurryx/proteusjs/transitions
|
|
15993
15993
|
* View Transitions API wrapper with safe fallbacks
|
|
15994
15994
|
*
|
|
15995
|
-
* @version
|
|
15995
|
+
* @version 2.0.0
|
|
15996
15996
|
* @author sc4rfurry
|
|
15997
15997
|
* @license MIT
|
|
15998
15998
|
*/
|
|
@@ -16027,11 +16027,11 @@ async function transition(run, opts = {}) {
|
|
|
16027
16027
|
// Add CSS view-transition-name if name provided
|
|
16028
16028
|
if (name) {
|
|
16029
16029
|
const style = document.createElement('style');
|
|
16030
|
-
style.textContent = `
|
|
16031
|
-
::view-transition-old(${name}),
|
|
16032
|
-
::view-transition-new(${name}) {
|
|
16033
|
-
animation-duration: ${duration}ms;
|
|
16034
|
-
}
|
|
16030
|
+
style.textContent = `
|
|
16031
|
+
::view-transition-old(${name}),
|
|
16032
|
+
::view-transition-new(${name}) {
|
|
16033
|
+
animation-duration: ${duration}ms;
|
|
16034
|
+
}
|
|
16035
16035
|
`;
|
|
16036
16036
|
document.head.appendChild(style);
|
|
16037
16037
|
// Clean up style after transition
|
|
@@ -16079,11 +16079,11 @@ async function navigate(url, opts = {}) {
|
|
|
16079
16079
|
});
|
|
16080
16080
|
if (name) {
|
|
16081
16081
|
const style = document.createElement('style');
|
|
16082
|
-
style.textContent = `
|
|
16083
|
-
::view-transition-old(${name}),
|
|
16084
|
-
::view-transition-new(${name}) {
|
|
16085
|
-
animation-duration: 300ms;
|
|
16086
|
-
}
|
|
16082
|
+
style.textContent = `
|
|
16083
|
+
::view-transition-old(${name}),
|
|
16084
|
+
::view-transition-new(${name}) {
|
|
16085
|
+
animation-duration: 300ms;
|
|
16086
|
+
}
|
|
16087
16087
|
`;
|
|
16088
16088
|
document.head.appendChild(style);
|
|
16089
16089
|
}
|
|
@@ -16111,7 +16111,7 @@ var index$h = /*#__PURE__*/Object.freeze({
|
|
|
16111
16111
|
* @sc4rfurryx/proteusjs/scroll
|
|
16112
16112
|
* Scroll-driven animations with CSS Scroll-Linked Animations
|
|
16113
16113
|
*
|
|
16114
|
-
* @version
|
|
16114
|
+
* @version 2.0.0
|
|
16115
16115
|
* @author sc4rfurry
|
|
16116
16116
|
* @license MIT
|
|
16117
16117
|
*/
|
|
@@ -16143,18 +16143,18 @@ function scrollAnimate(target, opts) {
|
|
|
16143
16143
|
const timelineName = `scroll-timeline-${Math.random().toString(36).substr(2, 9)}`;
|
|
16144
16144
|
// Create scroll timeline
|
|
16145
16145
|
const style = document.createElement('style');
|
|
16146
|
-
style.textContent = `
|
|
16147
|
-
@scroll-timeline ${timelineName} {
|
|
16148
|
-
source: nearest;
|
|
16149
|
-
orientation: ${axis};
|
|
16150
|
-
scroll-offsets: ${start}, ${end};
|
|
16151
|
-
}
|
|
16152
|
-
|
|
16153
|
-
.scroll-animate-${timelineName} {
|
|
16154
|
-
animation-timeline: ${timelineName};
|
|
16155
|
-
animation-duration: 1ms; /* Required but ignored */
|
|
16156
|
-
animation-fill-mode: both;
|
|
16157
|
-
}
|
|
16146
|
+
style.textContent = `
|
|
16147
|
+
@scroll-timeline ${timelineName} {
|
|
16148
|
+
source: nearest;
|
|
16149
|
+
orientation: ${axis};
|
|
16150
|
+
scroll-offsets: ${start}, ${end};
|
|
16151
|
+
}
|
|
16152
|
+
|
|
16153
|
+
.scroll-animate-${timelineName} {
|
|
16154
|
+
animation-timeline: ${timelineName};
|
|
16155
|
+
animation-duration: 1ms; /* Required but ignored */
|
|
16156
|
+
animation-fill-mode: both;
|
|
16157
|
+
}
|
|
16158
16158
|
`;
|
|
16159
16159
|
document.head.appendChild(style);
|
|
16160
16160
|
// Apply animation class
|
|
@@ -16307,7 +16307,7 @@ var index$f = /*#__PURE__*/Object.freeze({
|
|
|
16307
16307
|
* @sc4rfurryx/proteusjs/anchor
|
|
16308
16308
|
* CSS Anchor Positioning utilities with robust JS fallback
|
|
16309
16309
|
*
|
|
16310
|
-
* @version
|
|
16310
|
+
* @version 2.0.0
|
|
16311
16311
|
* @author sc4rfurry
|
|
16312
16312
|
* @license MIT
|
|
16313
16313
|
*/
|
|
@@ -16505,6 +16505,7 @@ function tether(floating, opts) {
|
|
|
16505
16505
|
setupJSFallback();
|
|
16506
16506
|
}
|
|
16507
16507
|
return {
|
|
16508
|
+
update: updatePosition,
|
|
16508
16509
|
destroy
|
|
16509
16510
|
};
|
|
16510
16511
|
}
|
|
@@ -16523,7 +16524,7 @@ var index$d = /*#__PURE__*/Object.freeze({
|
|
|
16523
16524
|
* @sc4rfurryx/proteusjs/popover
|
|
16524
16525
|
* HTML Popover API wrapper with robust focus/inert handling
|
|
16525
16526
|
*
|
|
16526
|
-
* @version
|
|
16527
|
+
* @version 2.0.0
|
|
16527
16528
|
* @author sc4rfurry
|
|
16528
16529
|
* @license MIT
|
|
16529
16530
|
*/
|
|
@@ -16712,7 +16713,7 @@ var index$b = /*#__PURE__*/Object.freeze({
|
|
|
16712
16713
|
* @sc4rfurryx/proteusjs/container
|
|
16713
16714
|
* Container/Style Query helpers with visualization devtools
|
|
16714
16715
|
*
|
|
16715
|
-
* @version
|
|
16716
|
+
* @version 2.0.0
|
|
16716
16717
|
* @author sc4rfurry
|
|
16717
16718
|
* @license MIT
|
|
16718
16719
|
*/
|
|
@@ -16746,43 +16747,43 @@ function defineContainer(target, name, opts = {}) {
|
|
|
16746
16747
|
function createDevOverlay(element, name) {
|
|
16747
16748
|
const overlay = document.createElement('div');
|
|
16748
16749
|
overlay.className = 'proteus-container-overlay';
|
|
16749
|
-
overlay.style.cssText = `
|
|
16750
|
-
position: absolute;
|
|
16751
|
-
top: 0;
|
|
16752
|
-
left: 0;
|
|
16753
|
-
right: 0;
|
|
16754
|
-
bottom: 0;
|
|
16755
|
-
pointer-events: none;
|
|
16756
|
-
border: 2px dashed rgba(255, 0, 255, 0.5);
|
|
16757
|
-
background: rgba(255, 0, 255, 0.05);
|
|
16758
|
-
z-index: 9999;
|
|
16759
|
-
font-family: monospace;
|
|
16760
|
-
font-size: 12px;
|
|
16761
|
-
color: #ff00ff;
|
|
16750
|
+
overlay.style.cssText = `
|
|
16751
|
+
position: absolute;
|
|
16752
|
+
top: 0;
|
|
16753
|
+
left: 0;
|
|
16754
|
+
right: 0;
|
|
16755
|
+
bottom: 0;
|
|
16756
|
+
pointer-events: none;
|
|
16757
|
+
border: 2px dashed rgba(255, 0, 255, 0.5);
|
|
16758
|
+
background: rgba(255, 0, 255, 0.05);
|
|
16759
|
+
z-index: 9999;
|
|
16760
|
+
font-family: monospace;
|
|
16761
|
+
font-size: 12px;
|
|
16762
|
+
color: #ff00ff;
|
|
16762
16763
|
`;
|
|
16763
16764
|
const label = document.createElement('div');
|
|
16764
|
-
label.style.cssText = `
|
|
16765
|
-
position: absolute;
|
|
16766
|
-
top: -20px;
|
|
16767
|
-
left: 0;
|
|
16768
|
-
background: rgba(255, 0, 255, 0.9);
|
|
16769
|
-
color: white;
|
|
16770
|
-
padding: 2px 6px;
|
|
16771
|
-
border-radius: 3px;
|
|
16772
|
-
font-size: 10px;
|
|
16773
|
-
white-space: nowrap;
|
|
16765
|
+
label.style.cssText = `
|
|
16766
|
+
position: absolute;
|
|
16767
|
+
top: -20px;
|
|
16768
|
+
left: 0;
|
|
16769
|
+
background: rgba(255, 0, 255, 0.9);
|
|
16770
|
+
color: white;
|
|
16771
|
+
padding: 2px 6px;
|
|
16772
|
+
border-radius: 3px;
|
|
16773
|
+
font-size: 10px;
|
|
16774
|
+
white-space: nowrap;
|
|
16774
16775
|
`;
|
|
16775
16776
|
label.textContent = `Container: ${name}`;
|
|
16776
16777
|
const sizeInfo = document.createElement('div');
|
|
16777
|
-
sizeInfo.style.cssText = `
|
|
16778
|
-
position: absolute;
|
|
16779
|
-
bottom: 2px;
|
|
16780
|
-
right: 2px;
|
|
16781
|
-
background: rgba(0, 0, 0, 0.7);
|
|
16782
|
-
color: white;
|
|
16783
|
-
padding: 2px 4px;
|
|
16784
|
-
border-radius: 2px;
|
|
16785
|
-
font-size: 10px;
|
|
16778
|
+
sizeInfo.style.cssText = `
|
|
16779
|
+
position: absolute;
|
|
16780
|
+
bottom: 2px;
|
|
16781
|
+
right: 2px;
|
|
16782
|
+
background: rgba(0, 0, 0, 0.7);
|
|
16783
|
+
color: white;
|
|
16784
|
+
padding: 2px 4px;
|
|
16785
|
+
border-radius: 2px;
|
|
16786
|
+
font-size: 10px;
|
|
16786
16787
|
`;
|
|
16787
16788
|
overlay.appendChild(label);
|
|
16788
16789
|
overlay.appendChild(sizeInfo);
|
|
@@ -16911,7 +16912,7 @@ var index$9 = /*#__PURE__*/Object.freeze({
|
|
|
16911
16912
|
* @sc4rfurryx/proteusjs/typography
|
|
16912
16913
|
* Fluid typography with CSS-first approach
|
|
16913
16914
|
*
|
|
16914
|
-
* @version
|
|
16915
|
+
* @version 2.0.0
|
|
16915
16916
|
* @author sc4rfurry
|
|
16916
16917
|
* @license MIT
|
|
16917
16918
|
*/
|
|
@@ -17083,504 +17084,59 @@ var index$7 = /*#__PURE__*/Object.freeze({
|
|
|
17083
17084
|
|
|
17084
17085
|
/**
|
|
17085
17086
|
* @sc4rfurryx/proteusjs/a11y-audit
|
|
17086
|
-
*
|
|
17087
|
+
* Lightweight accessibility audits for development
|
|
17087
17088
|
*
|
|
17088
|
-
* @version
|
|
17089
|
+
* @version 2.0.0
|
|
17089
17090
|
* @author sc4rfurry
|
|
17090
17091
|
* @license MIT
|
|
17091
17092
|
*/
|
|
17092
|
-
/**
|
|
17093
|
-
* Run accessibility audits with actionable output
|
|
17094
|
-
* DEV-ONLY: This module should be tree-shaken in production
|
|
17095
|
-
*/
|
|
17096
17093
|
async function audit(target = document, options = {}) {
|
|
17097
|
-
|
|
17098
|
-
|
|
17099
|
-
console.warn('a11y-audit should not be used in production');
|
|
17100
|
-
return {
|
|
17101
|
-
violations: [],
|
|
17102
|
-
passes: 0,
|
|
17103
|
-
incomplete: 0,
|
|
17104
|
-
timestamp: Date.now(),
|
|
17105
|
-
url: window.location.href
|
|
17106
|
-
};
|
|
17094
|
+
if (typeof window === 'undefined' || process.env['NODE_ENV'] === 'production') {
|
|
17095
|
+
return { violations: [], passes: 0, timestamp: Date.now(), url: '' };
|
|
17107
17096
|
}
|
|
17108
|
-
const { rules = ['
|
|
17097
|
+
const { rules = ['images', 'headings', 'forms'], format = 'console' } = options;
|
|
17109
17098
|
const violations = [];
|
|
17110
17099
|
let passes = 0;
|
|
17111
|
-
|
|
17112
|
-
|
|
17113
|
-
|
|
17114
|
-
'color-contrast': checkColorContrast,
|
|
17115
|
-
'heading-order': checkHeadingOrder,
|
|
17116
|
-
'image-alt': checkImageAlt,
|
|
17117
|
-
'label': checkFormLabels,
|
|
17118
|
-
'link-name': checkLinkNames,
|
|
17119
|
-
'button-name': checkButtonNames,
|
|
17120
|
-
'focus-visible': checkFocusVisible,
|
|
17121
|
-
'aria-labels': checkAriaLabels,
|
|
17122
|
-
'landmark-roles': checkLandmarkRoles,
|
|
17123
|
-
'skip-links': checkSkipLinks
|
|
17124
|
-
};
|
|
17125
|
-
// Run selected checks
|
|
17126
|
-
for (const ruleId of rules) {
|
|
17127
|
-
if (checks[ruleId]) {
|
|
17128
|
-
try {
|
|
17129
|
-
const result = await checks[ruleId](target);
|
|
17130
|
-
if (result.violations.length > 0) {
|
|
17131
|
-
violations.push(...result.violations);
|
|
17132
|
-
}
|
|
17133
|
-
else {
|
|
17134
|
-
passes++;
|
|
17135
|
-
}
|
|
17136
|
-
}
|
|
17137
|
-
catch (error) {
|
|
17138
|
-
incomplete++;
|
|
17139
|
-
console.warn(`Failed to run accessibility check: ${ruleId}`, error);
|
|
17140
|
-
}
|
|
17141
|
-
}
|
|
17142
|
-
}
|
|
17143
|
-
const report = {
|
|
17144
|
-
violations,
|
|
17145
|
-
passes,
|
|
17146
|
-
incomplete,
|
|
17147
|
-
timestamp: Date.now(),
|
|
17148
|
-
url: window.location.href
|
|
17149
|
-
};
|
|
17150
|
-
// Output results
|
|
17151
|
-
if (format === 'console') {
|
|
17152
|
-
outputToConsole(report);
|
|
17153
|
-
}
|
|
17154
|
-
if (openInBrowser) {
|
|
17155
|
-
openReportInBrowser(report);
|
|
17156
|
-
}
|
|
17157
|
-
return report;
|
|
17158
|
-
}
|
|
17159
|
-
// Individual check functions
|
|
17160
|
-
async function checkColorContrast(target) {
|
|
17161
|
-
const violations = [];
|
|
17162
|
-
const elements = target.querySelectorAll('*');
|
|
17163
|
-
elements.forEach(element => {
|
|
17164
|
-
const style = getComputedStyle(element);
|
|
17165
|
-
const color = style.color;
|
|
17166
|
-
const backgroundColor = style.backgroundColor;
|
|
17167
|
-
// Simple contrast check (would need more sophisticated implementation)
|
|
17168
|
-
if (color && backgroundColor && color !== 'rgba(0, 0, 0, 0)' && backgroundColor !== 'rgba(0, 0, 0, 0)') {
|
|
17169
|
-
const contrast = calculateContrast(color, backgroundColor);
|
|
17170
|
-
if (contrast < 4.5) {
|
|
17171
|
-
violations.push({
|
|
17172
|
-
id: 'color-contrast',
|
|
17173
|
-
impact: 'serious',
|
|
17174
|
-
nodes: 1,
|
|
17175
|
-
help: 'Elements must have sufficient color contrast',
|
|
17176
|
-
fix: `Increase contrast ratio to at least 4.5:1. Current: ${contrast.toFixed(2)}:1`,
|
|
17177
|
-
elements: [element]
|
|
17178
|
-
});
|
|
17179
|
-
}
|
|
17180
|
-
}
|
|
17181
|
-
});
|
|
17182
|
-
return { violations };
|
|
17183
|
-
}
|
|
17184
|
-
async function checkHeadingOrder(target) {
|
|
17185
|
-
const violations = [];
|
|
17186
|
-
const headings = target.querySelectorAll('h1, h2, h3, h4, h5, h6');
|
|
17187
|
-
let lastLevel = 0;
|
|
17188
|
-
headings.forEach(heading => {
|
|
17189
|
-
const level = parseInt(heading.tagName.charAt(1));
|
|
17190
|
-
if (level > lastLevel + 1) {
|
|
17100
|
+
if (rules.includes('images')) {
|
|
17101
|
+
const imgs = target.querySelectorAll('img:not([alt])');
|
|
17102
|
+
if (imgs.length > 0) {
|
|
17191
17103
|
violations.push({
|
|
17192
|
-
id: '
|
|
17193
|
-
impact: 'moderate',
|
|
17194
|
-
nodes: 1,
|
|
17195
|
-
help: 'Heading levels should only increase by one',
|
|
17196
|
-
fix: `Change ${heading.tagName} to H${lastLevel + 1} or add intermediate headings`,
|
|
17197
|
-
elements: [heading]
|
|
17104
|
+
id: 'image-alt', impact: 'critical', nodes: imgs.length, help: 'Images need alt text'
|
|
17198
17105
|
});
|
|
17199
17106
|
}
|
|
17200
|
-
|
|
17201
|
-
});
|
|
17202
|
-
return { violations };
|
|
17203
|
-
}
|
|
17204
|
-
async function checkImageAlt(target) {
|
|
17205
|
-
const violations = [];
|
|
17206
|
-
const images = target.querySelectorAll('img');
|
|
17207
|
-
images.forEach(img => {
|
|
17208
|
-
if (!img.hasAttribute('alt')) {
|
|
17209
|
-
violations.push({
|
|
17210
|
-
id: 'image-alt',
|
|
17211
|
-
impact: 'critical',
|
|
17212
|
-
nodes: 1,
|
|
17213
|
-
help: 'Images must have alternative text',
|
|
17214
|
-
fix: 'Add alt attribute with descriptive text or alt="" for decorative images',
|
|
17215
|
-
elements: [img]
|
|
17216
|
-
});
|
|
17217
|
-
}
|
|
17218
|
-
});
|
|
17219
|
-
return { violations };
|
|
17220
|
-
}
|
|
17221
|
-
async function checkFormLabels(target) {
|
|
17222
|
-
const violations = [];
|
|
17223
|
-
const inputs = target.querySelectorAll('input, select, textarea');
|
|
17224
|
-
inputs.forEach(input => {
|
|
17225
|
-
const hasLabel = input.hasAttribute('aria-label') ||
|
|
17226
|
-
input.hasAttribute('aria-labelledby') ||
|
|
17227
|
-
target.querySelector(`label[for="${input.id}"]`) ||
|
|
17228
|
-
input.closest('label');
|
|
17229
|
-
if (!hasLabel) {
|
|
17230
|
-
violations.push({
|
|
17231
|
-
id: 'label',
|
|
17232
|
-
impact: 'critical',
|
|
17233
|
-
nodes: 1,
|
|
17234
|
-
help: 'Form elements must have labels',
|
|
17235
|
-
fix: 'Add a label element, aria-label, or aria-labelledby attribute',
|
|
17236
|
-
elements: [input]
|
|
17237
|
-
});
|
|
17238
|
-
}
|
|
17239
|
-
});
|
|
17240
|
-
return { violations };
|
|
17241
|
-
}
|
|
17242
|
-
async function checkLinkNames(target) {
|
|
17243
|
-
const violations = [];
|
|
17244
|
-
const links = target.querySelectorAll('a[href]');
|
|
17245
|
-
links.forEach(link => {
|
|
17246
|
-
const text = link.textContent?.trim();
|
|
17247
|
-
const ariaLabel = link.getAttribute('aria-label');
|
|
17248
|
-
if (!text && !ariaLabel) {
|
|
17249
|
-
violations.push({
|
|
17250
|
-
id: 'link-name',
|
|
17251
|
-
impact: 'serious',
|
|
17252
|
-
nodes: 1,
|
|
17253
|
-
help: 'Links must have discernible text',
|
|
17254
|
-
fix: 'Add descriptive text content or aria-label attribute',
|
|
17255
|
-
elements: [link]
|
|
17256
|
-
});
|
|
17257
|
-
}
|
|
17258
|
-
});
|
|
17259
|
-
return { violations };
|
|
17260
|
-
}
|
|
17261
|
-
async function checkButtonNames(target) {
|
|
17262
|
-
const violations = [];
|
|
17263
|
-
const buttons = target.querySelectorAll('button, input[type="button"], input[type="submit"]');
|
|
17264
|
-
buttons.forEach(button => {
|
|
17265
|
-
const text = button.textContent?.trim();
|
|
17266
|
-
const ariaLabel = button.getAttribute('aria-label');
|
|
17267
|
-
const value = button.getAttribute('value');
|
|
17268
|
-
if (!text && !ariaLabel && !value) {
|
|
17269
|
-
violations.push({
|
|
17270
|
-
id: 'button-name',
|
|
17271
|
-
impact: 'serious',
|
|
17272
|
-
nodes: 1,
|
|
17273
|
-
help: 'Buttons must have discernible text',
|
|
17274
|
-
fix: 'Add text content, aria-label, or value attribute',
|
|
17275
|
-
elements: [button]
|
|
17276
|
-
});
|
|
17277
|
-
}
|
|
17278
|
-
});
|
|
17279
|
-
return { violations };
|
|
17280
|
-
}
|
|
17281
|
-
async function checkFocusVisible(target) {
|
|
17282
|
-
const violations = [];
|
|
17283
|
-
const focusableElements = target.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
|
|
17284
|
-
focusableElements.forEach(element => {
|
|
17285
|
-
const styles = getComputedStyle(element);
|
|
17286
|
-
const hasVisibleFocus = styles.outline !== 'none' && styles.outline !== '0px' &&
|
|
17287
|
-
styles.outline !== '0' && styles.outlineWidth !== '0px';
|
|
17288
|
-
// Check if element has custom focus styles
|
|
17289
|
-
const hasCustomFocus = styles.boxShadow.includes('inset') ||
|
|
17290
|
-
styles.border !== styles.borderColor ||
|
|
17291
|
-
element.hasAttribute('data-focus-visible');
|
|
17292
|
-
if (!hasVisibleFocus && !hasCustomFocus) {
|
|
17293
|
-
violations.push({
|
|
17294
|
-
id: 'focus-visible',
|
|
17295
|
-
impact: 'serious',
|
|
17296
|
-
nodes: 1,
|
|
17297
|
-
help: 'Interactive elements must have visible focus indicators',
|
|
17298
|
-
fix: 'Add outline, box-shadow, or other visible focus styles',
|
|
17299
|
-
elements: [element]
|
|
17300
|
-
});
|
|
17301
|
-
}
|
|
17302
|
-
});
|
|
17303
|
-
return { violations };
|
|
17304
|
-
}
|
|
17305
|
-
async function checkAriaLabels(target) {
|
|
17306
|
-
const violations = [];
|
|
17307
|
-
// Check for aria-labelledby pointing to non-existent elements
|
|
17308
|
-
const elementsWithLabelledBy = target.querySelectorAll('[aria-labelledby]');
|
|
17309
|
-
elementsWithLabelledBy.forEach(element => {
|
|
17310
|
-
const labelledBy = element.getAttribute('aria-labelledby');
|
|
17311
|
-
if (labelledBy) {
|
|
17312
|
-
const labelIds = labelledBy.split(' ');
|
|
17313
|
-
const missingIds = labelIds.filter(id => !target.querySelector(`#${id}`));
|
|
17314
|
-
if (missingIds.length > 0) {
|
|
17315
|
-
violations.push({
|
|
17316
|
-
id: 'aria-labelledby-invalid',
|
|
17317
|
-
impact: 'serious',
|
|
17318
|
-
nodes: 1,
|
|
17319
|
-
help: 'aria-labelledby must reference existing elements',
|
|
17320
|
-
fix: `Fix or remove references to missing IDs: ${missingIds.join(', ')}`,
|
|
17321
|
-
elements: [element]
|
|
17322
|
-
});
|
|
17323
|
-
}
|
|
17324
|
-
}
|
|
17325
|
-
});
|
|
17326
|
-
// Check for aria-describedby pointing to non-existent elements
|
|
17327
|
-
const elementsWithDescribedBy = target.querySelectorAll('[aria-describedby]');
|
|
17328
|
-
elementsWithDescribedBy.forEach(element => {
|
|
17329
|
-
const describedBy = element.getAttribute('aria-describedby');
|
|
17330
|
-
if (describedBy) {
|
|
17331
|
-
const descriptionIds = describedBy.split(' ');
|
|
17332
|
-
const missingIds = descriptionIds.filter(id => !target.querySelector(`#${id}`));
|
|
17333
|
-
if (missingIds.length > 0) {
|
|
17334
|
-
violations.push({
|
|
17335
|
-
id: 'aria-describedby-invalid',
|
|
17336
|
-
impact: 'moderate',
|
|
17337
|
-
nodes: 1,
|
|
17338
|
-
help: 'aria-describedby must reference existing elements',
|
|
17339
|
-
fix: `Fix or remove references to missing IDs: ${missingIds.join(', ')}`,
|
|
17340
|
-
elements: [element]
|
|
17341
|
-
});
|
|
17342
|
-
}
|
|
17343
|
-
}
|
|
17344
|
-
});
|
|
17345
|
-
return { violations };
|
|
17346
|
-
}
|
|
17347
|
-
async function checkLandmarkRoles(target) {
|
|
17348
|
-
const violations = [];
|
|
17349
|
-
// Check for missing main landmark
|
|
17350
|
-
const mainElements = target.querySelectorAll('main, [role="main"]');
|
|
17351
|
-
if (mainElements.length === 0) {
|
|
17352
|
-
violations.push({
|
|
17353
|
-
id: 'landmark-main-missing',
|
|
17354
|
-
impact: 'moderate',
|
|
17355
|
-
nodes: 0,
|
|
17356
|
-
help: 'Page should have a main landmark',
|
|
17357
|
-
fix: 'Add a <main> element or role="main" to identify the main content area'
|
|
17358
|
-
});
|
|
17359
|
-
}
|
|
17360
|
-
else if (mainElements.length > 1) {
|
|
17361
|
-
violations.push({
|
|
17362
|
-
id: 'landmark-main-multiple',
|
|
17363
|
-
impact: 'moderate',
|
|
17364
|
-
nodes: mainElements.length,
|
|
17365
|
-
help: 'Page should have only one main landmark',
|
|
17366
|
-
fix: 'Ensure only one main element or role="main" exists per page',
|
|
17367
|
-
elements: Array.from(mainElements)
|
|
17368
|
-
});
|
|
17369
|
-
}
|
|
17370
|
-
// Check for navigation landmarks without labels when multiple exist
|
|
17371
|
-
const navElements = target.querySelectorAll('nav, [role="navigation"]');
|
|
17372
|
-
if (navElements.length > 1) {
|
|
17373
|
-
navElements.forEach(nav => {
|
|
17374
|
-
const hasLabel = nav.hasAttribute('aria-label') ||
|
|
17375
|
-
nav.hasAttribute('aria-labelledby') ||
|
|
17376
|
-
nav.querySelector('h1, h2, h3, h4, h5, h6');
|
|
17377
|
-
if (!hasLabel) {
|
|
17378
|
-
violations.push({
|
|
17379
|
-
id: 'landmark-nav-unlabeled',
|
|
17380
|
-
impact: 'moderate',
|
|
17381
|
-
nodes: 1,
|
|
17382
|
-
help: 'Multiple navigation landmarks should be labeled',
|
|
17383
|
-
fix: 'Add aria-label or aria-labelledby to distinguish navigation areas',
|
|
17384
|
-
elements: [nav]
|
|
17385
|
-
});
|
|
17386
|
-
}
|
|
17387
|
-
});
|
|
17107
|
+
passes += target.querySelectorAll('img[alt]').length;
|
|
17388
17108
|
}
|
|
17389
|
-
|
|
17390
|
-
|
|
17391
|
-
|
|
17392
|
-
const violations = [];
|
|
17393
|
-
// Check for skip links in documents with navigation
|
|
17394
|
-
const navElements = target.querySelectorAll('nav, [role="navigation"]');
|
|
17395
|
-
const mainElement = target.querySelector('main, [role="main"]');
|
|
17396
|
-
if (navElements.length > 0 && mainElement) {
|
|
17397
|
-
const skipLinks = target.querySelectorAll('a[href^="#"]');
|
|
17398
|
-
const hasSkipToMain = Array.from(skipLinks).some(link => {
|
|
17399
|
-
const href = link.getAttribute('href');
|
|
17400
|
-
return href && (href === '#main' ||
|
|
17401
|
-
href === `#${mainElement.id}` ||
|
|
17402
|
-
link.textContent?.toLowerCase().includes('skip to main') ||
|
|
17403
|
-
link.textContent?.toLowerCase().includes('skip to content'));
|
|
17404
|
-
});
|
|
17405
|
-
if (!hasSkipToMain) {
|
|
17109
|
+
if (rules.includes('headings')) {
|
|
17110
|
+
const h1s = target.querySelectorAll('h1');
|
|
17111
|
+
if (h1s.length !== 1) {
|
|
17406
17112
|
violations.push({
|
|
17407
|
-
id: '
|
|
17408
|
-
impact: 'moderate',
|
|
17409
|
-
nodes: 0,
|
|
17410
|
-
help: 'Page with navigation should have skip links',
|
|
17411
|
-
fix: 'Add a skip link to the main content area for keyboard users'
|
|
17113
|
+
id: 'heading-structure', impact: 'moderate', nodes: h1s.length, help: 'Page should have exactly one h1'
|
|
17412
17114
|
});
|
|
17413
17115
|
}
|
|
17116
|
+
else
|
|
17117
|
+
passes++;
|
|
17414
17118
|
}
|
|
17415
|
-
|
|
17416
|
-
|
|
17417
|
-
|
|
17418
|
-
const href = firstFocusable.getAttribute('href');
|
|
17419
|
-
if (!href?.startsWith('#')) {
|
|
17119
|
+
if (rules.includes('forms')) {
|
|
17120
|
+
const unlabeled = target.querySelectorAll('input:not([aria-label]):not([aria-labelledby])');
|
|
17121
|
+
if (unlabeled.length > 0) {
|
|
17420
17122
|
violations.push({
|
|
17421
|
-
id: '
|
|
17422
|
-
impact: 'minor',
|
|
17423
|
-
nodes: 1,
|
|
17424
|
-
help: 'Skip links should be the first focusable elements',
|
|
17425
|
-
fix: 'Move skip links to the beginning of the document',
|
|
17426
|
-
elements: [firstFocusable]
|
|
17123
|
+
id: 'form-labels', impact: 'critical', nodes: unlabeled.length, help: 'Form inputs need labels'
|
|
17427
17124
|
});
|
|
17428
17125
|
}
|
|
17126
|
+
passes += target.querySelectorAll('input[aria-label], input[aria-labelledby]').length;
|
|
17429
17127
|
}
|
|
17430
|
-
|
|
17431
|
-
|
|
17432
|
-
|
|
17433
|
-
function calculateContrast(color1, color2) {
|
|
17434
|
-
// Convert colors to RGB values
|
|
17435
|
-
const rgb1 = parseColor(color1);
|
|
17436
|
-
const rgb2 = parseColor(color2);
|
|
17437
|
-
if (!rgb1 || !rgb2)
|
|
17438
|
-
return 4.5; // Fallback if parsing fails
|
|
17439
|
-
// Calculate relative luminance
|
|
17440
|
-
const l1 = getRelativeLuminance(rgb1);
|
|
17441
|
-
const l2 = getRelativeLuminance(rgb2);
|
|
17442
|
-
// Calculate contrast ratio
|
|
17443
|
-
const lighter = Math.max(l1, l2);
|
|
17444
|
-
const darker = Math.min(l1, l2);
|
|
17445
|
-
return (lighter + 0.05) / (darker + 0.05);
|
|
17446
|
-
}
|
|
17447
|
-
function parseColor(color) {
|
|
17448
|
-
// Handle rgb() format
|
|
17449
|
-
const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
|
|
17450
|
-
if (rgbMatch && rgbMatch[1] && rgbMatch[2] && rgbMatch[3]) {
|
|
17451
|
-
return {
|
|
17452
|
-
r: parseInt(rgbMatch[1], 10),
|
|
17453
|
-
g: parseInt(rgbMatch[2], 10),
|
|
17454
|
-
b: parseInt(rgbMatch[3], 10)
|
|
17455
|
-
};
|
|
17456
|
-
}
|
|
17457
|
-
// Handle hex format
|
|
17458
|
-
const hexMatch = color.match(/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i);
|
|
17459
|
-
if (hexMatch && hexMatch[1] && hexMatch[2] && hexMatch[3]) {
|
|
17460
|
-
return {
|
|
17461
|
-
r: parseInt(hexMatch[1], 16),
|
|
17462
|
-
g: parseInt(hexMatch[2], 16),
|
|
17463
|
-
b: parseInt(hexMatch[3], 16)
|
|
17464
|
-
};
|
|
17465
|
-
}
|
|
17466
|
-
// Handle named colors (basic set)
|
|
17467
|
-
const namedColors = {
|
|
17468
|
-
'black': { r: 0, g: 0, b: 0 },
|
|
17469
|
-
'white': { r: 255, g: 255, b: 255 },
|
|
17470
|
-
'red': { r: 255, g: 0, b: 0 },
|
|
17471
|
-
'green': { r: 0, g: 128, b: 0 },
|
|
17472
|
-
'blue': { r: 0, g: 0, b: 255 }
|
|
17128
|
+
const report = {
|
|
17129
|
+
violations, passes, timestamp: Date.now(),
|
|
17130
|
+
url: typeof window !== 'undefined' ? window.location.href : ''
|
|
17473
17131
|
};
|
|
17474
|
-
|
|
17475
|
-
|
|
17476
|
-
|
|
17477
|
-
|
|
17478
|
-
// Convert to sRGB
|
|
17479
|
-
const rsRGB = r / 255;
|
|
17480
|
-
const gsRGB = g / 255;
|
|
17481
|
-
const bsRGB = b / 255;
|
|
17482
|
-
// Apply gamma correction
|
|
17483
|
-
const rLinear = rsRGB <= 0.03928 ? rsRGB / 12.92 : Math.pow((rsRGB + 0.055) / 1.055, 2.4);
|
|
17484
|
-
const gLinear = gsRGB <= 0.03928 ? gsRGB / 12.92 : Math.pow((gsRGB + 0.055) / 1.055, 2.4);
|
|
17485
|
-
const bLinear = bsRGB <= 0.03928 ? bsRGB / 12.92 : Math.pow((bsRGB + 0.055) / 1.055, 2.4);
|
|
17486
|
-
// Calculate relative luminance
|
|
17487
|
-
return 0.2126 * rLinear + 0.7152 * gLinear + 0.0722 * bLinear;
|
|
17488
|
-
}
|
|
17489
|
-
function outputToConsole(report) {
|
|
17490
|
-
console.group('🔍 Accessibility Audit Results');
|
|
17491
|
-
if (report.violations.length === 0) {
|
|
17492
|
-
console.log('✅ No accessibility violations found!');
|
|
17493
|
-
}
|
|
17494
|
-
else {
|
|
17495
|
-
console.log(`❌ Found ${report.violations.length} accessibility violations:`);
|
|
17496
|
-
report.violations.forEach(violation => {
|
|
17497
|
-
const emoji = violation.impact === 'critical' ? '🚨' :
|
|
17498
|
-
violation.impact === 'serious' ? '⚠️' :
|
|
17499
|
-
violation.impact === 'moderate' ? '⚡' : 'ℹ️';
|
|
17500
|
-
console.group(`${emoji} ${violation.help}`);
|
|
17501
|
-
console.log(`Impact: ${violation.impact}`);
|
|
17502
|
-
console.log(`Fix: ${violation.fix}`);
|
|
17503
|
-
if (violation.elements) {
|
|
17504
|
-
console.log('Elements:', violation.elements);
|
|
17505
|
-
}
|
|
17506
|
-
console.groupEnd();
|
|
17507
|
-
});
|
|
17508
|
-
}
|
|
17509
|
-
console.log(`✅ ${report.passes} checks passed`);
|
|
17510
|
-
if (report.incomplete > 0) {
|
|
17511
|
-
console.log(`⚠️ ${report.incomplete} checks incomplete`);
|
|
17132
|
+
if (format === 'console' && violations.length > 0) {
|
|
17133
|
+
console.group('?? A11y Audit Results');
|
|
17134
|
+
violations.forEach(v => console.warn(`${v.impact}: ${v.help}`));
|
|
17135
|
+
console.groupEnd();
|
|
17512
17136
|
}
|
|
17513
|
-
|
|
17514
|
-
}
|
|
17515
|
-
function openReportInBrowser(report) {
|
|
17516
|
-
const html = generateHTMLReport(report);
|
|
17517
|
-
const blob = new Blob([html], { type: 'text/html' });
|
|
17518
|
-
const url = URL.createObjectURL(blob);
|
|
17519
|
-
const newWindow = window.open(url, '_blank');
|
|
17520
|
-
if (!newWindow) {
|
|
17521
|
-
console.warn('Could not open report in new window. Please check popup blocker settings.');
|
|
17522
|
-
// Fallback: download the report
|
|
17523
|
-
const link = document.createElement('a');
|
|
17524
|
-
link.href = url;
|
|
17525
|
-
link.download = `proteus-a11y-report-${Date.now()}.html`;
|
|
17526
|
-
link.click();
|
|
17527
|
-
}
|
|
17528
|
-
// Clean up the blob URL after a delay
|
|
17529
|
-
setTimeout(() => URL.revokeObjectURL(url), 1000);
|
|
17530
|
-
}
|
|
17531
|
-
function generateHTMLReport(report) {
|
|
17532
|
-
const violationsList = report.violations.map(violation => `
|
|
17533
|
-
<div class="violation violation--${violation.impact}">
|
|
17534
|
-
<h3>${violation.help}</h3>
|
|
17535
|
-
<p><strong>Impact:</strong> ${violation.impact}</p>
|
|
17536
|
-
<p><strong>Fix:</strong> ${violation.fix}</p>
|
|
17537
|
-
<p><strong>Affected elements:</strong> ${violation.nodes}</p>
|
|
17538
|
-
</div>
|
|
17539
|
-
`).join('');
|
|
17540
|
-
return `
|
|
17541
|
-
<!DOCTYPE html>
|
|
17542
|
-
<html lang="en">
|
|
17543
|
-
<head>
|
|
17544
|
-
<meta charset="UTF-8">
|
|
17545
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
17546
|
-
<title>ProteusJS Accessibility Report</title>
|
|
17547
|
-
<style>
|
|
17548
|
-
body { font-family: system-ui, sans-serif; margin: 2rem; line-height: 1.6; }
|
|
17549
|
-
.header { border-bottom: 2px solid #e5e7eb; padding-bottom: 1rem; margin-bottom: 2rem; }
|
|
17550
|
-
.summary { background: #f3f4f6; padding: 1rem; border-radius: 8px; margin-bottom: 2rem; }
|
|
17551
|
-
.violation { border-left: 4px solid #ef4444; padding: 1rem; margin-bottom: 1rem; background: #fef2f2; }
|
|
17552
|
-
.violation--critical { border-color: #dc2626; background: #fef2f2; }
|
|
17553
|
-
.violation--serious { border-color: #ea580c; background: #fff7ed; }
|
|
17554
|
-
.violation--moderate { border-color: #d97706; background: #fffbeb; }
|
|
17555
|
-
.violation--minor { border-color: #65a30d; background: #f7fee7; }
|
|
17556
|
-
.violation h3 { margin-top: 0; color: #374151; }
|
|
17557
|
-
.no-violations { text-align: center; color: #059669; font-size: 1.25rem; padding: 2rem; }
|
|
17558
|
-
</style>
|
|
17559
|
-
</head>
|
|
17560
|
-
<body>
|
|
17561
|
-
<div class="header">
|
|
17562
|
-
<h1>🌊 ProteusJS Accessibility Report</h1>
|
|
17563
|
-
<p>Generated on ${new Date(report.timestamp).toLocaleString()}</p>
|
|
17564
|
-
<p>URL: ${report.url}</p>
|
|
17565
|
-
</div>
|
|
17566
|
-
|
|
17567
|
-
<div class="summary">
|
|
17568
|
-
<h2>Summary</h2>
|
|
17569
|
-
<p><strong>Violations:</strong> ${report.violations.length}</p>
|
|
17570
|
-
<p><strong>Checks passed:</strong> ${report.passes}</p>
|
|
17571
|
-
<p><strong>Incomplete checks:</strong> ${report.incomplete}</p>
|
|
17572
|
-
</div>
|
|
17573
|
-
|
|
17574
|
-
${report.violations.length === 0 ?
|
|
17575
|
-
'<div class="no-violations">✅ No accessibility violations found!</div>' :
|
|
17576
|
-
`<h2>Violations</h2>${violationsList}`}
|
|
17577
|
-
</body>
|
|
17578
|
-
</html>`;
|
|
17137
|
+
return report;
|
|
17579
17138
|
}
|
|
17580
|
-
|
|
17581
|
-
var index$4 = {
|
|
17582
|
-
audit
|
|
17583
|
-
};
|
|
17139
|
+
var index$4 = { audit };
|
|
17584
17140
|
|
|
17585
17141
|
var index$5 = /*#__PURE__*/Object.freeze({
|
|
17586
17142
|
__proto__: null,
|
|
@@ -17590,450 +17146,116 @@ var index$5 = /*#__PURE__*/Object.freeze({
|
|
|
17590
17146
|
|
|
17591
17147
|
/**
|
|
17592
17148
|
* @sc4rfurryx/proteusjs/a11y-primitives
|
|
17593
|
-
*
|
|
17149
|
+
* Lightweight accessibility patterns
|
|
17594
17150
|
*
|
|
17595
|
-
* @version
|
|
17151
|
+
* @version 2.0.0
|
|
17596
17152
|
* @author sc4rfurry
|
|
17597
17153
|
* @license MIT
|
|
17598
17154
|
*/
|
|
17599
|
-
/**
|
|
17600
|
-
* Dialog primitive with proper ARIA and focus management
|
|
17601
|
-
*/
|
|
17602
17155
|
function dialog(root, opts = {}) {
|
|
17603
|
-
const
|
|
17604
|
-
if (!
|
|
17605
|
-
throw new Error('Dialog
|
|
17156
|
+
const el = typeof root === 'string' ? document.querySelector(root) : root;
|
|
17157
|
+
if (!el)
|
|
17158
|
+
throw new Error('Dialog element not found');
|
|
17606
17159
|
const { modal = true, restoreFocus = true } = opts;
|
|
17607
|
-
|
|
17608
|
-
const setup = () => {
|
|
17609
|
-
rootEl.setAttribute('role', 'dialog');
|
|
17610
|
-
if (modal) {
|
|
17611
|
-
rootEl.setAttribute('aria-modal', 'true');
|
|
17612
|
-
}
|
|
17613
|
-
// Ensure dialog is initially hidden
|
|
17614
|
-
if (!rootEl.hasAttribute('hidden')) {
|
|
17615
|
-
rootEl.setAttribute('hidden', '');
|
|
17616
|
-
}
|
|
17617
|
-
};
|
|
17618
|
-
const handleKeyDown = (e) => {
|
|
17619
|
-
if (e.key === 'Escape' && isOpen) ;
|
|
17620
|
-
};
|
|
17621
|
-
setup();
|
|
17622
|
-
document.addEventListener('keydown', handleKeyDown);
|
|
17623
|
-
return {
|
|
17624
|
-
destroy: () => {
|
|
17625
|
-
document.removeEventListener('keydown', handleKeyDown);
|
|
17626
|
-
}
|
|
17160
|
+
const close = () => {
|
|
17627
17161
|
};
|
|
17162
|
+
return { destroy: () => close() };
|
|
17628
17163
|
}
|
|
17629
|
-
|
|
17630
|
-
|
|
17631
|
-
|
|
17632
|
-
function tooltip(trigger, panel, opts = {}) {
|
|
17633
|
-
const triggerEl = typeof trigger === 'string' ? document.querySelector(trigger) : trigger;
|
|
17634
|
-
const panelEl = typeof panel === 'string' ? document.querySelector(panel) : panel;
|
|
17635
|
-
if (!triggerEl || !panelEl) {
|
|
17636
|
-
throw new Error('Both trigger and panel elements must exist');
|
|
17637
|
-
}
|
|
17638
|
-
const { delay = 500 } = opts;
|
|
17639
|
-
let timeoutId = null;
|
|
17640
|
-
let isVisible = false;
|
|
17641
|
-
const setup = () => {
|
|
17642
|
-
const tooltipId = panelEl.id || `tooltip-${Math.random().toString(36).substring(2, 11)}`;
|
|
17643
|
-
panelEl.id = tooltipId;
|
|
17644
|
-
panelEl.setAttribute('role', 'tooltip');
|
|
17645
|
-
triggerEl.setAttribute('aria-describedby', tooltipId);
|
|
17646
|
-
// Initially hidden
|
|
17647
|
-
panelEl.style.display = 'none';
|
|
17648
|
-
};
|
|
17164
|
+
function tooltip(trigger, content, opts = {}) {
|
|
17165
|
+
const { delay = 300 } = opts;
|
|
17166
|
+
let timeout;
|
|
17649
17167
|
const show = () => {
|
|
17650
|
-
|
|
17651
|
-
|
|
17652
|
-
|
|
17653
|
-
|
|
17168
|
+
clearTimeout(timeout);
|
|
17169
|
+
timeout = window.setTimeout(() => {
|
|
17170
|
+
content.setAttribute('role', 'tooltip');
|
|
17171
|
+
trigger.setAttribute('aria-describedby', content.id || 'tooltip');
|
|
17172
|
+
content.style.display = 'block';
|
|
17173
|
+
}, delay);
|
|
17654
17174
|
};
|
|
17655
17175
|
const hide = () => {
|
|
17656
|
-
|
|
17657
|
-
|
|
17658
|
-
|
|
17659
|
-
isVisible = false;
|
|
17660
|
-
};
|
|
17661
|
-
const handleMouseEnter = () => {
|
|
17662
|
-
if (timeoutId)
|
|
17663
|
-
clearTimeout(timeoutId);
|
|
17664
|
-
timeoutId = window.setTimeout(show, delay);
|
|
17665
|
-
};
|
|
17666
|
-
const handleMouseLeave = () => {
|
|
17667
|
-
if (timeoutId) {
|
|
17668
|
-
clearTimeout(timeoutId);
|
|
17669
|
-
timeoutId = null;
|
|
17670
|
-
}
|
|
17671
|
-
hide();
|
|
17672
|
-
};
|
|
17673
|
-
const handleFocus = () => {
|
|
17674
|
-
show();
|
|
17675
|
-
};
|
|
17676
|
-
const handleBlur = () => {
|
|
17677
|
-
hide();
|
|
17176
|
+
clearTimeout(timeout);
|
|
17177
|
+
content.style.display = 'none';
|
|
17178
|
+
trigger.removeAttribute('aria-describedby');
|
|
17678
17179
|
};
|
|
17679
|
-
|
|
17680
|
-
|
|
17681
|
-
|
|
17682
|
-
|
|
17683
|
-
triggerEl.addEventListener('blur', handleBlur);
|
|
17180
|
+
trigger.addEventListener('mouseenter', show);
|
|
17181
|
+
trigger.addEventListener('mouseleave', hide);
|
|
17182
|
+
trigger.addEventListener('focus', show);
|
|
17183
|
+
trigger.addEventListener('blur', hide);
|
|
17684
17184
|
return {
|
|
17685
17185
|
destroy: () => {
|
|
17686
|
-
|
|
17687
|
-
|
|
17688
|
-
|
|
17689
|
-
|
|
17690
|
-
|
|
17691
|
-
triggerEl.removeEventListener('blur', handleBlur);
|
|
17692
|
-
hide();
|
|
17186
|
+
clearTimeout(timeout);
|
|
17187
|
+
trigger.removeEventListener('mouseenter', show);
|
|
17188
|
+
trigger.removeEventListener('mouseleave', hide);
|
|
17189
|
+
trigger.removeEventListener('focus', show);
|
|
17190
|
+
trigger.removeEventListener('blur', hide);
|
|
17693
17191
|
}
|
|
17694
17192
|
};
|
|
17695
17193
|
}
|
|
17696
|
-
|
|
17697
|
-
|
|
17698
|
-
|
|
17699
|
-
|
|
17700
|
-
|
|
17701
|
-
if (!rootEl)
|
|
17702
|
-
throw new Error('Listbox root element not found');
|
|
17703
|
-
const { multiselect = false } = opts;
|
|
17704
|
-
let currentIndex = -1;
|
|
17705
|
-
const setup = () => {
|
|
17706
|
-
rootEl.setAttribute('role', 'listbox');
|
|
17707
|
-
if (multiselect) {
|
|
17708
|
-
rootEl.setAttribute('aria-multiselectable', 'true');
|
|
17709
|
-
}
|
|
17710
|
-
// Set up options
|
|
17711
|
-
const options = rootEl.querySelectorAll('[role="option"]');
|
|
17712
|
-
options.forEach((option, _index) => {
|
|
17713
|
-
option.setAttribute('aria-selected', 'false');
|
|
17714
|
-
option.setAttribute('tabindex', '-1');
|
|
17715
|
-
});
|
|
17716
|
-
if (options.length > 0) {
|
|
17717
|
-
options[0]?.setAttribute('tabindex', '0');
|
|
17718
|
-
currentIndex = 0;
|
|
17719
|
-
}
|
|
17720
|
-
};
|
|
17721
|
-
const getOptions = () => rootEl.querySelectorAll('[role="option"]');
|
|
17722
|
-
const setCurrentIndex = (index) => {
|
|
17723
|
-
const options = getOptions();
|
|
17724
|
-
if (index < 0 || index >= options.length)
|
|
17725
|
-
return;
|
|
17726
|
-
// Remove tabindex from all options
|
|
17727
|
-
options.forEach(option => option.setAttribute('tabindex', '-1'));
|
|
17728
|
-
// Set current option
|
|
17729
|
-
currentIndex = index;
|
|
17730
|
-
options[currentIndex]?.setAttribute('tabindex', '0');
|
|
17731
|
-
options[currentIndex]?.focus();
|
|
17732
|
-
};
|
|
17733
|
-
const selectOption = (index) => {
|
|
17734
|
-
const options = getOptions();
|
|
17735
|
-
if (index < 0 || index >= options.length)
|
|
17736
|
-
return;
|
|
17737
|
-
if (multiselect) {
|
|
17738
|
-
const isSelected = options[index]?.getAttribute('aria-selected') === 'true';
|
|
17739
|
-
options[index]?.setAttribute('aria-selected', (!isSelected).toString());
|
|
17740
|
-
}
|
|
17741
|
-
else {
|
|
17742
|
-
// Single select - clear all others
|
|
17743
|
-
options.forEach(option => option.setAttribute('aria-selected', 'false'));
|
|
17744
|
-
options[index]?.setAttribute('aria-selected', 'true');
|
|
17745
|
-
}
|
|
17746
|
-
};
|
|
17747
|
-
const handleKeyDown = (e) => {
|
|
17748
|
-
const keyEvent = e;
|
|
17749
|
-
const options = getOptions();
|
|
17750
|
-
switch (keyEvent.key) {
|
|
17751
|
-
case 'ArrowDown':
|
|
17752
|
-
keyEvent.preventDefault();
|
|
17753
|
-
setCurrentIndex(Math.min(currentIndex + 1, options.length - 1));
|
|
17754
|
-
break;
|
|
17755
|
-
case 'ArrowUp':
|
|
17756
|
-
keyEvent.preventDefault();
|
|
17757
|
-
setCurrentIndex(Math.max(currentIndex - 1, 0));
|
|
17758
|
-
break;
|
|
17759
|
-
case 'Home':
|
|
17760
|
-
keyEvent.preventDefault();
|
|
17761
|
-
setCurrentIndex(0);
|
|
17762
|
-
break;
|
|
17763
|
-
case 'End':
|
|
17764
|
-
keyEvent.preventDefault();
|
|
17765
|
-
setCurrentIndex(options.length - 1);
|
|
17766
|
-
break;
|
|
17767
|
-
case 'Enter':
|
|
17768
|
-
case ' ':
|
|
17769
|
-
keyEvent.preventDefault();
|
|
17770
|
-
selectOption(currentIndex);
|
|
17771
|
-
break;
|
|
17772
|
-
}
|
|
17773
|
-
};
|
|
17774
|
-
const handleClick = (e) => {
|
|
17775
|
-
const target = e.target;
|
|
17776
|
-
const option = target.closest('[role="option"]');
|
|
17777
|
-
if (!option)
|
|
17194
|
+
function focusTrap(container) {
|
|
17195
|
+
const focusable = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
17196
|
+
const activate = () => {
|
|
17197
|
+
const elements = container.querySelectorAll(focusable);
|
|
17198
|
+
if (elements.length === 0)
|
|
17778
17199
|
return;
|
|
17779
|
-
const
|
|
17780
|
-
const
|
|
17781
|
-
|
|
17782
|
-
|
|
17783
|
-
|
|
17784
|
-
|
|
17785
|
-
|
|
17786
|
-
|
|
17787
|
-
rootEl.addEventListener('keydown', handleKeyDown);
|
|
17788
|
-
rootEl.addEventListener('click', handleClick);
|
|
17789
|
-
return {
|
|
17790
|
-
destroy: () => {
|
|
17791
|
-
rootEl.removeEventListener('keydown', handleKeyDown);
|
|
17792
|
-
rootEl.removeEventListener('click', handleClick);
|
|
17793
|
-
}
|
|
17794
|
-
};
|
|
17795
|
-
}
|
|
17796
|
-
/**
|
|
17797
|
-
* Combobox primitive with filtering and multiselect
|
|
17798
|
-
*/
|
|
17799
|
-
function combobox(root, opts = {}) {
|
|
17800
|
-
const rootEl = typeof root === 'string' ? document.querySelector(root) : root;
|
|
17801
|
-
if (!rootEl)
|
|
17802
|
-
throw new Error('Combobox root element not found');
|
|
17803
|
-
const { multiselect = false, filtering: _filtering } = opts;
|
|
17804
|
-
let isOpen = false;
|
|
17805
|
-
const setup = () => {
|
|
17806
|
-
rootEl.setAttribute('role', 'combobox');
|
|
17807
|
-
rootEl.setAttribute('aria-expanded', 'false');
|
|
17808
|
-
if (multiselect) {
|
|
17809
|
-
rootEl.setAttribute('aria-multiselectable', 'true');
|
|
17810
|
-
}
|
|
17811
|
-
};
|
|
17812
|
-
const handleKeyDown = (e) => {
|
|
17813
|
-
const keyEvent = e;
|
|
17814
|
-
switch (keyEvent.key) {
|
|
17815
|
-
case 'ArrowDown':
|
|
17816
|
-
keyEvent.preventDefault();
|
|
17817
|
-
if (!isOpen) {
|
|
17818
|
-
isOpen = true;
|
|
17819
|
-
rootEl.setAttribute('aria-expanded', 'true');
|
|
17820
|
-
}
|
|
17821
|
-
// Navigate options logic would go here
|
|
17822
|
-
break;
|
|
17823
|
-
case 'Escape':
|
|
17824
|
-
keyEvent.preventDefault();
|
|
17825
|
-
isOpen = false;
|
|
17826
|
-
rootEl.setAttribute('aria-expanded', 'false');
|
|
17827
|
-
break;
|
|
17828
|
-
}
|
|
17829
|
-
};
|
|
17830
|
-
setup();
|
|
17831
|
-
rootEl.addEventListener('keydown', handleKeyDown);
|
|
17832
|
-
return {
|
|
17833
|
-
destroy: () => {
|
|
17834
|
-
rootEl.removeEventListener('keydown', handleKeyDown);
|
|
17835
|
-
}
|
|
17836
|
-
};
|
|
17837
|
-
}
|
|
17838
|
-
/**
|
|
17839
|
-
* Tabs primitive with keyboard navigation
|
|
17840
|
-
*/
|
|
17841
|
-
function tabs(root) {
|
|
17842
|
-
const rootEl = typeof root === 'string' ? document.querySelector(root) : root;
|
|
17843
|
-
if (!rootEl)
|
|
17844
|
-
throw new Error('Tabs root element not found');
|
|
17845
|
-
let currentIndex = 0;
|
|
17846
|
-
const setup = () => {
|
|
17847
|
-
const tabList = rootEl.querySelector('[role="tablist"]');
|
|
17848
|
-
const tabs = rootEl.querySelectorAll('[role="tab"]');
|
|
17849
|
-
const panels = rootEl.querySelectorAll('[role="tabpanel"]');
|
|
17850
|
-
if (!tabList) {
|
|
17851
|
-
rootEl.setAttribute('role', 'tablist');
|
|
17852
|
-
}
|
|
17853
|
-
tabs.forEach((tab, index) => {
|
|
17854
|
-
tab.setAttribute('tabindex', index === 0 ? '0' : '-1');
|
|
17855
|
-
tab.setAttribute('aria-selected', index === 0 ? 'true' : 'false');
|
|
17856
|
-
});
|
|
17857
|
-
panels.forEach((panel, index) => {
|
|
17858
|
-
panel.setAttribute('hidden', index === 0 ? '' : 'true');
|
|
17859
|
-
});
|
|
17860
|
-
};
|
|
17861
|
-
const handleKeyDown = (e) => {
|
|
17862
|
-
const keyEvent = e;
|
|
17863
|
-
const tabs = Array.from(rootEl.querySelectorAll('[role="tab"]'));
|
|
17864
|
-
switch (keyEvent.key) {
|
|
17865
|
-
case 'ArrowRight':
|
|
17866
|
-
keyEvent.preventDefault();
|
|
17867
|
-
currentIndex = (currentIndex + 1) % tabs.length;
|
|
17868
|
-
activateTab(currentIndex);
|
|
17869
|
-
break;
|
|
17870
|
-
case 'ArrowLeft':
|
|
17871
|
-
keyEvent.preventDefault();
|
|
17872
|
-
currentIndex = currentIndex === 0 ? tabs.length - 1 : currentIndex - 1;
|
|
17873
|
-
activateTab(currentIndex);
|
|
17874
|
-
break;
|
|
17875
|
-
}
|
|
17876
|
-
};
|
|
17877
|
-
const activateTab = (index) => {
|
|
17878
|
-
const tabs = rootEl.querySelectorAll('[role="tab"]');
|
|
17879
|
-
const panels = rootEl.querySelectorAll('[role="tabpanel"]');
|
|
17880
|
-
tabs.forEach((tab, i) => {
|
|
17881
|
-
tab.setAttribute('tabindex', i === index ? '0' : '-1');
|
|
17882
|
-
tab.setAttribute('aria-selected', i === index ? 'true' : 'false');
|
|
17883
|
-
if (i === index) {
|
|
17884
|
-
tab.focus();
|
|
17885
|
-
}
|
|
17886
|
-
});
|
|
17887
|
-
panels.forEach((panel, i) => {
|
|
17888
|
-
if (i === index) {
|
|
17889
|
-
panel.removeAttribute('hidden');
|
|
17200
|
+
const first = elements[0];
|
|
17201
|
+
const last = elements[elements.length - 1];
|
|
17202
|
+
const handleTab = (e) => {
|
|
17203
|
+
if (e.key !== 'Tab')
|
|
17204
|
+
return;
|
|
17205
|
+
if (e.shiftKey && document.activeElement === first) {
|
|
17206
|
+
e.preventDefault();
|
|
17207
|
+
last.focus();
|
|
17890
17208
|
}
|
|
17891
|
-
else {
|
|
17892
|
-
|
|
17209
|
+
else if (!e.shiftKey && document.activeElement === last) {
|
|
17210
|
+
e.preventDefault();
|
|
17211
|
+
first.focus();
|
|
17893
17212
|
}
|
|
17894
|
-
}
|
|
17213
|
+
};
|
|
17214
|
+
container.addEventListener('keydown', handleTab);
|
|
17215
|
+
first.focus();
|
|
17216
|
+
return () => container.removeEventListener('keydown', handleTab);
|
|
17895
17217
|
};
|
|
17896
|
-
|
|
17897
|
-
rootEl.addEventListener('keydown', handleKeyDown);
|
|
17218
|
+
let deactivate = () => { };
|
|
17898
17219
|
return {
|
|
17899
|
-
|
|
17900
|
-
|
|
17901
|
-
}
|
|
17220
|
+
activate: () => { deactivate = activate() || (() => { }); },
|
|
17221
|
+
deactivate: () => deactivate()
|
|
17902
17222
|
};
|
|
17903
17223
|
}
|
|
17904
|
-
|
|
17905
|
-
|
|
17906
|
-
|
|
17907
|
-
|
|
17908
|
-
|
|
17909
|
-
if (!rootEl)
|
|
17910
|
-
throw new Error('Menu root element not found');
|
|
17911
|
-
let currentIndex = -1;
|
|
17912
|
-
const setup = () => {
|
|
17913
|
-
rootEl.setAttribute('role', 'menu');
|
|
17914
|
-
const items = rootEl.querySelectorAll('[role="menuitem"]');
|
|
17915
|
-
items.forEach((item, index) => {
|
|
17916
|
-
item.setAttribute('tabindex', index === 0 ? '0' : '-1');
|
|
17917
|
-
});
|
|
17918
|
-
if (items.length > 0) {
|
|
17919
|
-
currentIndex = 0;
|
|
17920
|
-
}
|
|
17921
|
-
};
|
|
17922
|
-
const handleKeyDown = (e) => {
|
|
17923
|
-
const keyEvent = e;
|
|
17924
|
-
const items = Array.from(rootEl.querySelectorAll('[role="menuitem"]'));
|
|
17925
|
-
switch (keyEvent.key) {
|
|
17224
|
+
function menu(container) {
|
|
17225
|
+
const items = container.querySelectorAll('[role="menuitem"]');
|
|
17226
|
+
let currentIndex = 0;
|
|
17227
|
+
const navigate = (e) => {
|
|
17228
|
+
switch (e.key) {
|
|
17926
17229
|
case 'ArrowDown':
|
|
17927
|
-
|
|
17230
|
+
e.preventDefault();
|
|
17928
17231
|
currentIndex = (currentIndex + 1) % items.length;
|
|
17929
|
-
|
|
17232
|
+
items[currentIndex].focus();
|
|
17930
17233
|
break;
|
|
17931
17234
|
case 'ArrowUp':
|
|
17932
|
-
|
|
17235
|
+
e.preventDefault();
|
|
17933
17236
|
currentIndex = currentIndex === 0 ? items.length - 1 : currentIndex - 1;
|
|
17934
|
-
|
|
17237
|
+
items[currentIndex].focus();
|
|
17935
17238
|
break;
|
|
17936
|
-
case '
|
|
17937
|
-
case ' ':
|
|
17938
|
-
keyEvent.preventDefault();
|
|
17939
|
-
if (items[currentIndex]) {
|
|
17940
|
-
items[currentIndex].click();
|
|
17941
|
-
}
|
|
17942
|
-
break;
|
|
17943
|
-
}
|
|
17944
|
-
};
|
|
17945
|
-
const setCurrentItem = (index) => {
|
|
17946
|
-
const items = rootEl.querySelectorAll('[role="menuitem"]');
|
|
17947
|
-
items.forEach((item, i) => {
|
|
17948
|
-
item.setAttribute('tabindex', i === index ? '0' : '-1');
|
|
17949
|
-
if (i === index) {
|
|
17950
|
-
item.focus();
|
|
17951
|
-
}
|
|
17952
|
-
});
|
|
17953
|
-
};
|
|
17954
|
-
setup();
|
|
17955
|
-
rootEl.addEventListener('keydown', handleKeyDown);
|
|
17956
|
-
return {
|
|
17957
|
-
destroy: () => {
|
|
17958
|
-
rootEl.removeEventListener('keydown', handleKeyDown);
|
|
17959
|
-
}
|
|
17960
|
-
};
|
|
17961
|
-
}
|
|
17962
|
-
/**
|
|
17963
|
-
* Focus trap utility
|
|
17964
|
-
*/
|
|
17965
|
-
function focusTrap(root) {
|
|
17966
|
-
const rootEl = typeof root === 'string' ? document.querySelector(root) : root;
|
|
17967
|
-
if (!rootEl)
|
|
17968
|
-
throw new Error('Focus trap root element not found');
|
|
17969
|
-
let isActive = false;
|
|
17970
|
-
let focusableElements = [];
|
|
17971
|
-
const updateFocusableElements = () => {
|
|
17972
|
-
const selector = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
17973
|
-
focusableElements = Array.from(rootEl.querySelectorAll(selector));
|
|
17974
|
-
};
|
|
17975
|
-
const handleKeyDown = (e) => {
|
|
17976
|
-
if (!isActive || e.key !== 'Tab')
|
|
17977
|
-
return;
|
|
17978
|
-
updateFocusableElements();
|
|
17979
|
-
if (focusableElements.length === 0)
|
|
17980
|
-
return;
|
|
17981
|
-
const firstElement = focusableElements[0];
|
|
17982
|
-
const lastElement = focusableElements[focusableElements.length - 1];
|
|
17983
|
-
if (e.shiftKey) {
|
|
17984
|
-
if (document.activeElement === firstElement) {
|
|
17985
|
-
e.preventDefault();
|
|
17986
|
-
lastElement.focus();
|
|
17987
|
-
}
|
|
17988
|
-
}
|
|
17989
|
-
else {
|
|
17990
|
-
if (document.activeElement === lastElement) {
|
|
17239
|
+
case 'Escape':
|
|
17991
17240
|
e.preventDefault();
|
|
17992
|
-
|
|
17993
|
-
|
|
17994
|
-
}
|
|
17995
|
-
};
|
|
17996
|
-
const activate = () => {
|
|
17997
|
-
if (isActive)
|
|
17998
|
-
return;
|
|
17999
|
-
isActive = true;
|
|
18000
|
-
updateFocusableElements();
|
|
18001
|
-
if (focusableElements.length > 0) {
|
|
18002
|
-
focusableElements[0].focus();
|
|
17241
|
+
container.dispatchEvent(new CustomEvent('menu:close'));
|
|
17242
|
+
break;
|
|
18003
17243
|
}
|
|
18004
|
-
document.addEventListener('keydown', handleKeyDown);
|
|
18005
|
-
};
|
|
18006
|
-
const deactivate = () => {
|
|
18007
|
-
if (!isActive)
|
|
18008
|
-
return;
|
|
18009
|
-
isActive = false;
|
|
18010
|
-
document.removeEventListener('keydown', handleKeyDown);
|
|
18011
17244
|
};
|
|
17245
|
+
container.setAttribute('role', 'menu');
|
|
17246
|
+
container.addEventListener('keydown', navigate);
|
|
18012
17247
|
return {
|
|
18013
|
-
|
|
18014
|
-
deactivate
|
|
17248
|
+
destroy: () => container.removeEventListener('keydown', navigate)
|
|
18015
17249
|
};
|
|
18016
17250
|
}
|
|
18017
|
-
|
|
18018
|
-
var index$2 = {
|
|
18019
|
-
dialog,
|
|
18020
|
-
tooltip,
|
|
18021
|
-
combobox,
|
|
18022
|
-
listbox,
|
|
18023
|
-
tabs,
|
|
18024
|
-
menu,
|
|
18025
|
-
focusTrap
|
|
18026
|
-
};
|
|
17251
|
+
var index$2 = { dialog, tooltip, focusTrap, menu };
|
|
18027
17252
|
|
|
18028
17253
|
var index$3 = /*#__PURE__*/Object.freeze({
|
|
18029
17254
|
__proto__: null,
|
|
18030
|
-
combobox: combobox,
|
|
18031
17255
|
default: index$2,
|
|
18032
17256
|
dialog: dialog,
|
|
18033
17257
|
focusTrap: focusTrap,
|
|
18034
|
-
listbox: listbox,
|
|
18035
17258
|
menu: menu,
|
|
18036
|
-
tabs: tabs,
|
|
18037
17259
|
tooltip: tooltip
|
|
18038
17260
|
});
|
|
18039
17261
|
|
|
@@ -18041,7 +17263,7 @@ var index$3 = /*#__PURE__*/Object.freeze({
|
|
|
18041
17263
|
* @sc4rfurryx/proteusjs/perf
|
|
18042
17264
|
* Performance guardrails and CWV-friendly patterns
|
|
18043
17265
|
*
|
|
18044
|
-
* @version
|
|
17266
|
+
* @version 2.0.0
|
|
18045
17267
|
* @author sc4rfurry
|
|
18046
17268
|
* @license MIT
|
|
18047
17269
|
*/
|
|
@@ -18303,13 +17525,13 @@ var index$1 = /*#__PURE__*/Object.freeze({
|
|
|
18303
17525
|
* ProteusJS - Native-first Web Development Primitives
|
|
18304
17526
|
* Shape-shifting responsive design that adapts like the sea god himself
|
|
18305
17527
|
*
|
|
18306
|
-
* @version
|
|
17528
|
+
* @version 2.0.0
|
|
18307
17529
|
* @author sc4rfurry
|
|
18308
17530
|
* @license MIT
|
|
18309
17531
|
*/
|
|
18310
17532
|
// Core exports (legacy compatibility)
|
|
18311
17533
|
// Constants
|
|
18312
|
-
const VERSION = '
|
|
17534
|
+
const VERSION = '2.0.0';
|
|
18313
17535
|
const LIBRARY_NAME = 'ProteusJS';
|
|
18314
17536
|
|
|
18315
17537
|
export { LIBRARY_NAME, ProteusJS, VERSION, index$5 as a11yAudit, index$3 as a11yPrimitives, index$d as anchor, index$9 as container, ProteusJS as default, isSupported$1 as isSupported, index$1 as perf, index$b as popover, index$f as scroll, index$h as transitions, index$7 as typography, version };
|