@gjsify/adwaita-web 0.62.0 → 0.63.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 +31 -0
- package/lib/types/elements/gtk-window.d.ts +33 -0
- package/lib/types/pango-markup.d.ts +10 -0
- package/lib/types/pango-markup.spec.d.ts +1 -0
- package/lib/types/source-view/copy-glyph.d.ts +6 -0
- package/lib/types/source-view/copy-glyph.spec.d.ts +1 -0
- package/package.json +11 -11
- package/src/application.spec.ts +33 -0
- package/src/application.ts +16 -0
- package/src/elements/adw-alert-dialog.ts +8 -5
- package/src/elements/adw-banner.ts +14 -9
- package/src/elements/gtk-window.ts +146 -11
- package/src/gtk-window.spec.ts +122 -0
- package/src/pango-markup.spec.ts +257 -0
- package/src/pango-markup.ts +266 -0
- package/src/source-view/adw-source-view.ts +2 -8
- package/src/source-view/copy-glyph.spec.ts +46 -0
- package/src/source-view/copy-glyph.ts +52 -0
- package/src/test.browser.mts +4 -0
|
@@ -35,13 +35,7 @@ import { asm6502 } from './asm6502.js';
|
|
|
35
35
|
import { adwaitaEditorTheme, adwaitaHighlightStyle, ensureSourceViewStyleInjected } from './theme.js';
|
|
36
36
|
import { formatHexAddress, formatLineNumber, stripSourceWhitespace } from '@gjsify/adwaita-core';
|
|
37
37
|
import { createGtkImage } from '../elements/gtk-image.js';
|
|
38
|
-
|
|
39
|
-
/** A recognisable copy glyph rendered inline so the subpath needs no icon CSS. */
|
|
40
|
-
const COPY_SVG =
|
|
41
|
-
'<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">' +
|
|
42
|
-
'<path d="M4 1a2 2 0 0 0-2 2v7h2V3h6V1H4z"/>' +
|
|
43
|
-
'<path d="M7 4a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h5a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H7zm0 2h5v7H7V6z"/>' +
|
|
44
|
-
'</svg>';
|
|
38
|
+
import { createCopyGlyph } from './copy-glyph.js';
|
|
45
39
|
|
|
46
40
|
/** Parse a boolean attribute: present (any value but "false") ⇒ true. */
|
|
47
41
|
function boolAttr(value: string | null): boolean {
|
|
@@ -400,7 +394,7 @@ export class AdwSourceView extends HTMLElement {
|
|
|
400
394
|
private _renderCopyIcon(): void {
|
|
401
395
|
const name = this._copyButtonIcon || 'edit-copy';
|
|
402
396
|
if (name === 'edit-copy' || name === 'copy' || name === '') {
|
|
403
|
-
this._copyButton.
|
|
397
|
+
this._copyButton.replaceChildren(createCopyGlyph(this._copyButton.ownerDocument));
|
|
404
398
|
return;
|
|
405
399
|
}
|
|
406
400
|
// A non-default icon uses the adwaita-web mask class (requires the main
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// The copy glyph the `<adw-source-view>` copy button draws.
|
|
2
|
+
//
|
|
3
|
+
// The regression this holds: the glyph WAS a constant SVG string assigned with
|
|
4
|
+
// `innerHTML`. Constant and safe-until-edited, and the reviewer who flagged the two
|
|
5
|
+
// `use-markup` sinks in the same package flagged the shape, so it is built from nodes now.
|
|
6
|
+
// These rows are the ones a re-parsing implementation would fail: the namespace, the
|
|
7
|
+
// element names, and that nothing about it arrives as a string the browser parsed.
|
|
8
|
+
|
|
9
|
+
import { describe, expect, it } from '@gjsify/unit';
|
|
10
|
+
|
|
11
|
+
import { createCopyGlyph } from './copy-glyph.js';
|
|
12
|
+
|
|
13
|
+
export const CopyGlyphTest = async () => {
|
|
14
|
+
await describe('createCopyGlyph — the copy button still has its icon', async () => {
|
|
15
|
+
await it('is an <svg> in the SVG namespace, sized and viewBox-ed like every other glyph', () => {
|
|
16
|
+
const glyph = createCopyGlyph();
|
|
17
|
+
expect(glyph.namespaceURI).toBe('http://www.w3.org/2000/svg');
|
|
18
|
+
expect(glyph.tagName).toBe('svg');
|
|
19
|
+
expect(glyph.getAttribute('width')).toBe('16');
|
|
20
|
+
expect(glyph.getAttribute('height')).toBe('16');
|
|
21
|
+
expect(glyph.getAttribute('viewBox')).toBe('0 0 16 16');
|
|
22
|
+
// The button owns the accessible name; the glyph is decoration inside it.
|
|
23
|
+
expect(glyph.getAttribute('aria-hidden')).toBe('true');
|
|
24
|
+
expect(glyph.getAttribute('fill')).toBe('currentColor');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
await it('draws the two sheets as <path> elements, each with a real outline', () => {
|
|
28
|
+
const glyph = createCopyGlyph();
|
|
29
|
+
const paths = [...glyph.children];
|
|
30
|
+
expect(paths.map((el) => el.tagName)).toStrictEqual(['path', 'path']);
|
|
31
|
+
for (const path of paths) {
|
|
32
|
+
expect(path.namespaceURI).toBe('http://www.w3.org/2000/svg');
|
|
33
|
+
expect((path.getAttribute('d') ?? '').length).toBeGreaterThan(10);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
await it('lands in a button as a drawable glyph', () => {
|
|
38
|
+
const button = document.createElement('button');
|
|
39
|
+
document.body.appendChild(button);
|
|
40
|
+
button.replaceChildren(createCopyGlyph(button.ownerDocument));
|
|
41
|
+
expect(button.querySelector('svg')).not.toBe(null);
|
|
42
|
+
expect(button.getBoundingClientRect().height).toBeGreaterThan(0);
|
|
43
|
+
button.remove();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// The copy button's glyph, built as NODES.
|
|
2
|
+
//
|
|
3
|
+
// It was a constant SVG string handed to `innerHTML`, which is safe only until someone
|
|
4
|
+
// edits the string — and it was, next to two `use-markup` surfaces that did the same with
|
|
5
|
+
// AUTHOR-controlled markup, the reason Mozilla's add-on reviewer flagged this package.
|
|
6
|
+
// The glyph is a constant and the sink was not: `createElementNS` costs two lines more and
|
|
7
|
+
// cannot parse anything.
|
|
8
|
+
//
|
|
9
|
+
// It lives in its own module, not in `pango-markup.ts` (which is about Pango markup) and
|
|
10
|
+
// not inline in `adw-source-view.ts` (which would drag CodeMirror into any suite that
|
|
11
|
+
// wants to check the shape) — so a test can assert the glyph without pulling the editor in.
|
|
12
|
+
//
|
|
13
|
+
// The two paths are the two sheets of the `edit-copy` mark: the back sheet offset up-left,
|
|
14
|
+
// the front sheet inset. `aria-hidden` because the button carries the accessible name, the
|
|
15
|
+
// same split `gtk-image.ts` documents.
|
|
16
|
+
//
|
|
17
|
+
// Reference: refs/adwaita-icon-theme/Adwaita/scalable/status-icons/edit-copy-symbolic.svg
|
|
18
|
+
// (the same two-sheet mark, path data rounded to integers here)
|
|
19
|
+
// Copyright (c) 2025 gjsify contributors. MIT License.
|
|
20
|
+
|
|
21
|
+
/** The SVG namespace, spelled once — `createElementNS` needs it on every node. */
|
|
22
|
+
const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
23
|
+
|
|
24
|
+
/** The two sheet outlines, in draw order (back, then front). */
|
|
25
|
+
const SHEETS = [
|
|
26
|
+
'M4 1a2 2 0 0 0-2 2v7h2V3h6V1H4z',
|
|
27
|
+
'M7 4a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h5a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H7zm0 2h5v7H7V6z',
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
/** The size both spinners and every symbolic icon in this package draw at. */
|
|
31
|
+
const GLYPH_SIZE = '16';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A recognisable copy glyph rendered inline so the opt-in `source-view` subpath needs no
|
|
35
|
+
* icon CSS. `doc` is a parameter so a caller outside the main document (a shadow root in
|
|
36
|
+
* another frame) gets nodes its own tree can adopt.
|
|
37
|
+
*/
|
|
38
|
+
export function createCopyGlyph(doc: Document = document): SVGSVGElement {
|
|
39
|
+
const svg = doc.createElementNS(SVG_NS, 'svg');
|
|
40
|
+
svg.setAttribute('width', GLYPH_SIZE);
|
|
41
|
+
svg.setAttribute('height', GLYPH_SIZE);
|
|
42
|
+
svg.setAttribute('viewBox', `0 0 ${GLYPH_SIZE} ${GLYPH_SIZE}`);
|
|
43
|
+
svg.setAttribute('fill', 'currentColor');
|
|
44
|
+
svg.setAttribute('aria-hidden', 'true');
|
|
45
|
+
|
|
46
|
+
for (const d of SHEETS) {
|
|
47
|
+
const path = doc.createElementNS(SVG_NS, 'path');
|
|
48
|
+
path.setAttribute('d', d);
|
|
49
|
+
svg.append(path);
|
|
50
|
+
}
|
|
51
|
+
return svg;
|
|
52
|
+
}
|
package/src/test.browser.mts
CHANGED
|
@@ -59,6 +59,8 @@ import { GtkAboutDialogTest } from './gtk-about-dialog.spec.js';
|
|
|
59
59
|
import { GtkEmojiChooserTest } from './gtk-emoji-chooser.spec.js';
|
|
60
60
|
import { GtkPrintDialogsTest } from './gtk-print-dialogs.spec.js';
|
|
61
61
|
import { AdwBannerTest } from './adw-banner.spec.js';
|
|
62
|
+
import { PangoMarkupTest } from './pango-markup.spec.js';
|
|
63
|
+
import { CopyGlyphTest } from './source-view/copy-glyph.spec.js';
|
|
62
64
|
import { AdwButtonContentTest } from './adw-button-content.spec.js';
|
|
63
65
|
import { GtkImageTest } from './gtk-image.spec.js';
|
|
64
66
|
import { AdwIconRegistryTest } from './icon-registry.spec.js';
|
|
@@ -191,6 +193,8 @@ run({
|
|
|
191
193
|
AdwAboutDialogTest,
|
|
192
194
|
AdwAlertDialogTest,
|
|
193
195
|
AdwBannerTest,
|
|
196
|
+
PangoMarkupTest,
|
|
197
|
+
CopyGlyphTest,
|
|
194
198
|
AdwButtonContentTest,
|
|
195
199
|
GtkImageTest,
|
|
196
200
|
AdwIconRegistryTest,
|