jig-ui 0.18.0 → 0.18.1
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/CHANGELOG.md +35 -0
- package/dist/index.js +45 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.18.1
|
|
4
|
+
|
|
5
|
+
Two fixes found by jig-site's fourth round: the probe misread a `<details>`
|
|
6
|
+
menu, and `A-05` missed an arrow that renders as an emoji.
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- **The probe reads a `<details>` menu the way the browser shows it.** On
|
|
11
|
+
jig-site's Reference it reported a working phone menu as broken, and
|
|
12
|
+
`jig verdicts` refused a correct `P-14` verdict on the strength of it. Four
|
|
13
|
+
defects, each now covered by a browser test:
|
|
14
|
+
- Where the banner's menu is hidden at a width, the probe took the next
|
|
15
|
+
disclosure in some other `<nav>` (a docs rail's section tree) as the menu,
|
|
16
|
+
and reported "a menu button beside links that already show". A menu the
|
|
17
|
+
page names, or one in its banner, is now the only candidate once it exists.
|
|
18
|
+
- A closed `<details>` hides its content with `content-visibility` in
|
|
19
|
+
Chromium, which still gives its links boxes, so the closed menu's links
|
|
20
|
+
counted as showing and opening it "showed no more links". Visibility now
|
|
21
|
+
also asks `checkVisibility()`.
|
|
22
|
+
- A label swapped with CSS ("Menu" to "Close") keeps both words in
|
|
23
|
+
`textContent`; the label is now read from the rendered text.
|
|
24
|
+
- A native `<summary>` has no `aria-expanded` attribute; its expanded state
|
|
25
|
+
is its `<details>`'s `open`, which is what assistive technology is given.
|
|
26
|
+
|
|
27
|
+
Probe files are now version 6, so earlier ones are re-recorded.
|
|
28
|
+
|
|
29
|
+
- **`A-05` catches an arrow that turns into an emoji.** ↔ ↕ ↖ ↗ ↘ ↙ ↩ ↪ ▶ ◀
|
|
30
|
+
are text by default but have an emoji form, and the detector skipped the
|
|
31
|
+
whole arrow block so prose arrows would not fire. jig-site marked its
|
|
32
|
+
external links with `<span aria-hidden="true">↗</span>`, which some platforms
|
|
33
|
+
draw as a colour emoji, and `check --all` and three critiques passed it. One
|
|
34
|
+
of these characters now fires when it stands alone as an icon (the whole
|
|
35
|
+
content of an element, or a pseudo-element's `content`) without U+FE0E. The
|
|
36
|
+
same arrow in a sentence still does not.
|
|
37
|
+
|
|
3
38
|
## 0.18.0
|
|
4
39
|
|
|
5
40
|
A page's frame gets tokens, a project gets a place to record where its layout
|
package/dist/index.js
CHANGED
|
@@ -2265,6 +2265,11 @@ function maskProseComments(raw) {
|
|
|
2265
2265
|
// src/check/detectors/emoji-icon.ts
|
|
2266
2266
|
var EMOJI_RE = /[\u{1F300}-\u{1FAFF}\u{1F000}-\u{1F2FF}\u{2600}-\u{27BF}\u{2B00}-\u{2BFF}\u{FE0F}]/gu;
|
|
2267
2267
|
var TEXTUAL = /* @__PURE__ */ new Set(["\u2192", "\u2190", "\u2191", "\u2193", "\u2194", "\u21D2", "\u21D0", "\u2122", "\u2713", "\u2717", "\u2212", "\u2217", "\u2318", "\u2325", "\u23CE"]);
|
|
2268
|
+
var EMOJI_CAPABLE = "\\u2194-\\u2199\\u21A9\\u21AA\\u25B6\\u25C0";
|
|
2269
|
+
var LONE_GLYPH = new RegExp(
|
|
2270
|
+
`>\\s*([${EMOJI_CAPABLE}])(?!\\uFE0E)\\s*<|content\\s*:\\s*["']([${EMOJI_CAPABLE}])(?!\\uFE0E)["']`,
|
|
2271
|
+
"gu"
|
|
2272
|
+
);
|
|
2268
2273
|
var emojiIcon = {
|
|
2269
2274
|
name: "emoji-icon",
|
|
2270
2275
|
appliesTo: (file) => isStyleBearing(file),
|
|
@@ -2289,6 +2294,22 @@ var emojiIcon = {
|
|
|
2289
2294
|
)
|
|
2290
2295
|
);
|
|
2291
2296
|
}
|
|
2297
|
+
for (const m of masked.matchAll(LONE_GLYPH)) {
|
|
2298
|
+
const glyph = m[1] ?? m[2];
|
|
2299
|
+
const line = masked.slice(0, m.index + m[0].indexOf(glyph)).split("\n").length;
|
|
2300
|
+
if (seen.has(line)) continue;
|
|
2301
|
+
seen.add(line);
|
|
2302
|
+
findings.push(
|
|
2303
|
+
mkFinding(
|
|
2304
|
+
ctx,
|
|
2305
|
+
"emoji-icon",
|
|
2306
|
+
file,
|
|
2307
|
+
line,
|
|
2308
|
+
`A character with an emoji form used as an icon (${glyph}). Standing alone, it renders as a colour emoji on some platforms. Use an icon set, or words.`,
|
|
2309
|
+
lines[line - 1] ?? ""
|
|
2310
|
+
)
|
|
2311
|
+
);
|
|
2312
|
+
}
|
|
2292
2313
|
return findings;
|
|
2293
2314
|
}
|
|
2294
2315
|
};
|
|
@@ -5676,10 +5697,13 @@ import { fileURLToPath as fileURLToPath2 } from "url";
|
|
|
5676
5697
|
import { join as join33, relative as relative3, resolve as resolve4, sep as sep5 } from "path";
|
|
5677
5698
|
|
|
5678
5699
|
// src/probe/script.ts
|
|
5679
|
-
var PROBE_VERSION =
|
|
5700
|
+
var PROBE_VERSION = 6;
|
|
5680
5701
|
var PROBE_SCRIPT = `(async () => {
|
|
5681
5702
|
const doc = document.documentElement;
|
|
5682
|
-
|
|
5703
|
+
// checkVisibility also sees content a closed <details> hides: Chromium hides
|
|
5704
|
+
// it with content-visibility, which still gives its links real boxes, so a
|
|
5705
|
+
// closed menu counted as open and an opened one showed "no more links".
|
|
5706
|
+
const vis = (e) => { const r = e.getBoundingClientRect(); const s = getComputedStyle(e); return r.width > 0 && r.height > 0 && s.visibility !== 'hidden' && s.display !== 'none' && (!e.checkVisibility || e.checkVisibility()); };
|
|
5683
5707
|
const probe = document.createElement('div');
|
|
5684
5708
|
probe.style.all = 'initial';
|
|
5685
5709
|
document.body.appendChild(probe);
|
|
@@ -5772,19 +5796,32 @@ var PROBE_SCRIPT = `(async () => {
|
|
|
5772
5796
|
const inChrome = (b) => !!b.closest('header, [role=banner]') ||
|
|
5773
5797
|
(!!b.closest('nav, [role=navigation]') && !b.closest('main, article, aside, [role=main]'));
|
|
5774
5798
|
const named = (b) => /\b(menu|navigation)\b/i.test((b.getAttribute('aria-label') || '') + ' ' + b.textContent);
|
|
5775
|
-
const
|
|
5776
|
-
|
|
5799
|
+
const candidates = [...document.querySelectorAll('button, summary, [role=button]')].filter((b) =>
|
|
5800
|
+
named(b) || (inChrome(b) && (b.tagName === 'SUMMARY' || b.hasAttribute('aria-expanded') || b.hasAttribute('aria-controls'))));
|
|
5801
|
+
// A menu the page names, or one in its banner, is the menu. Where it exists
|
|
5802
|
+
// but is hidden at this width, the links show instead and there is no menu
|
|
5803
|
+
// here; the next disclosure in some other <nav> (a docs rail's tree) is not
|
|
5804
|
+
// a stand-in for it.
|
|
5805
|
+
const primary = (b) => named(b) || !!b.closest('header, [role=banner]');
|
|
5806
|
+
const pool = candidates.some(primary) ? candidates.filter(primary) : candidates;
|
|
5807
|
+
const toggle = pool.find(vis);
|
|
5777
5808
|
let menu = null;
|
|
5778
5809
|
if (toggle) {
|
|
5779
|
-
|
|
5810
|
+
// The label as rendered: a menu that swaps "Menu" for "Close" with CSS keeps
|
|
5811
|
+
// both words in its textContent at all times, so only innerText sees the swap.
|
|
5812
|
+
const name = () => ((toggle.getAttribute('aria-label') || '') + ' ' + (toggle.innerText || toggle.textContent || '')).replace(/\\s+/g, ' ').trim();
|
|
5813
|
+
// A native <summary> carries no aria-expanded attribute; the browser exposes
|
|
5814
|
+
// its <details>'s open state as the expanded state, which is what counts.
|
|
5815
|
+
const expanded = () => toggle.getAttribute('aria-expanded') ??
|
|
5816
|
+
(toggle.tagName === 'SUMMARY' && toggle.parentElement && toggle.parentElement.tagName === 'DETAILS' ? String(toggle.parentElement.open) : null);
|
|
5780
5817
|
// Opening is judged by what becomes visible anywhere: a menu panel is often
|
|
5781
5818
|
// a sibling of the header, not inside it (arm test 3, tw-1).
|
|
5782
5819
|
const allLinks = () => [...document.querySelectorAll('a')].filter(vis).length;
|
|
5783
5820
|
const controlled = () => { const id = toggle.getAttribute('aria-controls'); const el = id && document.getElementById(id); return el ? vis(el) : null; };
|
|
5784
|
-
const before = { links: allLinks(), controlled: controlled(), expanded:
|
|
5821
|
+
const before = { links: allLinks(), controlled: controlled(), expanded: expanded(), name: name(), html: toggle.innerHTML };
|
|
5785
5822
|
toggle.click();
|
|
5786
5823
|
await new Promise((r) => setTimeout(r, 350));
|
|
5787
|
-
const after = { links: allLinks(), controlled: controlled(), expanded:
|
|
5824
|
+
const after = { links: allLinks(), controlled: controlled(), expanded: expanded(), name: name(), htmlChanged: toggle.innerHTML !== before.html };
|
|
5788
5825
|
toggle.focus();
|
|
5789
5826
|
toggle.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
5790
5827
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
@@ -5794,7 +5831,7 @@ var PROBE_SCRIPT = `(async () => {
|
|
|
5794
5831
|
expandedBefore: before.expanded, expandedAfter: after.expanded,
|
|
5795
5832
|
opened: after.links > before.links || (before.controlled === false && after.controlled === true),
|
|
5796
5833
|
labelChanged: after.name !== before.name || after.htmlChanged,
|
|
5797
|
-
escapeCloses:
|
|
5834
|
+
escapeCloses: expanded() !== 'true' && allLinks() <= before.links,
|
|
5798
5835
|
focusReturned: document.activeElement === toggle,
|
|
5799
5836
|
};
|
|
5800
5837
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jig-ui",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"description": "A design system for coding agents. 143 numbered UI rules, brand x mode design tokens, and an installer for Claude Code, Codex, Cursor and opencode.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|