@gjsify/adwaita-web 0.64.1 → 0.64.2-next.254
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 +22 -88
- package/dist/adwaita-web.css +91 -12
- package/dist/adwaita-web.css.map +1 -1
- package/lib/types/accessible.d.ts +8 -0
- package/lib/types/application.d.ts +1 -1
- package/lib/types/child-slot.spec.d.ts +1 -0
- package/lib/types/compute-expand.d.ts +5 -0
- package/lib/types/compute-expand.spec.d.ts +1 -0
- package/lib/types/container-fill.spec.d.ts +1 -0
- package/lib/types/elements/adw-about-dialog.d.ts +28 -1
- package/lib/types/elements/adw-action-row.d.ts +2 -1
- package/lib/types/elements/adw-alert-dialog.d.ts +80 -19
- package/lib/types/elements/adw-avatar.d.ts +2 -1
- package/lib/types/elements/adw-banner.d.ts +2 -1
- package/lib/types/elements/adw-bin.d.ts +2 -1
- package/lib/types/elements/adw-bottom-sheet.d.ts +5 -4
- package/lib/types/elements/adw-breakpoint-bin.d.ts +2 -1
- package/lib/types/elements/adw-button-content.d.ts +2 -1
- package/lib/types/elements/adw-button-row.d.ts +2 -1
- package/lib/types/elements/adw-card.d.ts +2 -1
- package/lib/types/elements/adw-carousel.d.ts +20 -3
- package/lib/types/elements/adw-clamp-scrollable.d.ts +2 -1
- package/lib/types/elements/adw-clamp.d.ts +2 -1
- package/lib/types/elements/adw-combo-row.d.ts +6 -1
- package/lib/types/elements/adw-data-grid.d.ts +2 -1
- package/lib/types/elements/adw-dialog.d.ts +2 -1
- package/lib/types/elements/adw-entry-row.d.ts +2 -1
- package/lib/types/elements/adw-expander-row.d.ts +2 -1
- package/lib/types/elements/adw-header-bar.d.ts +2 -1
- package/lib/types/elements/adw-inline-view-switcher.d.ts +3 -2
- package/lib/types/elements/adw-layout-slot.d.ts +2 -1
- package/lib/types/elements/adw-multi-layout-view.d.ts +2 -1
- package/lib/types/elements/adw-navigation-split-view.d.ts +2 -1
- package/lib/types/elements/adw-navigation-view.d.ts +3 -2
- package/lib/types/elements/adw-overlay-split-view.d.ts +2 -1
- package/lib/types/elements/adw-preferences-dialog.d.ts +5 -4
- package/lib/types/elements/adw-preferences-group.d.ts +2 -1
- package/lib/types/elements/adw-preferences-row.d.ts +2 -1
- package/lib/types/elements/adw-shortcut-label.d.ts +2 -1
- package/lib/types/elements/adw-shortcuts-item.d.ts +2 -1
- package/lib/types/elements/adw-shortcuts-section.d.ts +2 -1
- package/lib/types/elements/adw-sidebar.d.ts +4 -3
- package/lib/types/elements/adw-spin-row.d.ts +2 -1
- package/lib/types/elements/adw-spinner.d.ts +2 -1
- package/lib/types/elements/adw-split-button.d.ts +2 -1
- package/lib/types/elements/adw-status-page.d.ts +2 -1
- package/lib/types/elements/adw-switch-row.d.ts +4 -1
- package/lib/types/elements/adw-tab-bar.d.ts +2 -1
- package/lib/types/elements/adw-tab-button.d.ts +2 -1
- package/lib/types/elements/adw-tab-overview.d.ts +2 -1
- package/lib/types/elements/adw-tab-view.d.ts +3 -2
- package/lib/types/elements/adw-toast-overlay.d.ts +10 -30
- package/lib/types/elements/adw-toggle-group.d.ts +3 -2
- package/lib/types/elements/adw-toolbar-view.d.ts +2 -1
- package/lib/types/elements/adw-view-stack.d.ts +3 -1
- package/lib/types/elements/adw-view-switcher-bar.d.ts +2 -1
- package/lib/types/elements/adw-view-switcher-sidebar.d.ts +2 -1
- package/lib/types/elements/adw-view-switcher.d.ts +3 -2
- package/lib/types/elements/adw-window-features.d.ts +8 -0
- package/lib/types/elements/adw-window-title.d.ts +2 -1
- package/lib/types/elements/adw-wrap-box.d.ts +2 -1
- package/lib/types/elements/checks.d.ts +16 -1
- package/lib/types/elements/gtk-action-bar.d.ts +2 -1
- package/lib/types/elements/gtk-application-window.d.ts +1 -4
- package/lib/types/elements/gtk-aspect-frame.d.ts +2 -1
- package/lib/types/elements/gtk-box.d.ts +5 -1
- package/lib/types/elements/gtk-button.d.ts +5 -7
- package/lib/types/elements/gtk-calendar.d.ts +2 -1
- package/lib/types/elements/gtk-center-box.d.ts +2 -1
- package/lib/types/elements/gtk-color-dialog-button.d.ts +2 -1
- package/lib/types/elements/gtk-drag-icon.d.ts +2 -1
- package/lib/types/elements/gtk-drawing-area.d.ts +2 -1
- package/lib/types/elements/gtk-drop-down.d.ts +2 -1
- package/lib/types/elements/gtk-editable-label.d.ts +2 -1
- package/lib/types/elements/gtk-emoji-chooser.d.ts +2 -0
- package/lib/types/elements/gtk-entry.d.ts +2 -1
- package/lib/types/elements/gtk-expander.d.ts +2 -1
- package/lib/types/elements/gtk-fixed.d.ts +2 -1
- package/lib/types/elements/gtk-flow-box-child.d.ts +2 -1
- package/lib/types/elements/gtk-flow-box.d.ts +2 -1
- package/lib/types/elements/gtk-font-dialog-button.d.ts +2 -1
- package/lib/types/elements/gtk-frame.d.ts +2 -1
- package/lib/types/elements/gtk-gl-area.d.ts +2 -1
- package/lib/types/elements/gtk-graphics-offload.d.ts +2 -1
- package/lib/types/elements/gtk-grid.d.ts +2 -1
- package/lib/types/elements/gtk-header-bar.d.ts +2 -1
- package/lib/types/elements/gtk-image.d.ts +5 -6
- package/lib/types/elements/gtk-inscription.d.ts +2 -1
- package/lib/types/elements/gtk-label.d.ts +10 -3
- package/lib/types/elements/gtk-level-bar.d.ts +2 -1
- package/lib/types/elements/gtk-list-box-row.d.ts +2 -1
- package/lib/types/elements/gtk-list-box.d.ts +2 -1
- package/lib/types/elements/gtk-list-view.d.ts +2 -1
- package/lib/types/elements/gtk-media-controls.d.ts +2 -1
- package/lib/types/elements/gtk-menu-button.d.ts +2 -1
- package/lib/types/elements/gtk-notebook.d.ts +2 -1
- package/lib/types/elements/gtk-overlay.d.ts +2 -1
- package/lib/types/elements/gtk-paned.d.ts +2 -1
- package/lib/types/elements/gtk-picture.d.ts +2 -1
- package/lib/types/elements/gtk-popover-bin.d.ts +2 -1
- package/lib/types/elements/gtk-popover-menu-bar.d.ts +2 -1
- package/lib/types/elements/gtk-popover-menu.d.ts +2 -0
- package/lib/types/elements/gtk-popover.d.ts +7 -1
- package/lib/types/elements/gtk-progress-bar.d.ts +2 -1
- package/lib/types/elements/gtk-revealer.d.ts +2 -1
- package/lib/types/elements/gtk-scale-button.d.ts +2 -1
- package/lib/types/elements/gtk-scale.d.ts +2 -1
- package/lib/types/elements/gtk-scrollbar.d.ts +2 -1
- package/lib/types/elements/gtk-scrolled-window.d.ts +2 -1
- package/lib/types/elements/gtk-search-bar.d.ts +2 -1
- package/lib/types/elements/gtk-separator.d.ts +2 -1
- package/lib/types/elements/gtk-spin-button.d.ts +2 -1
- package/lib/types/elements/gtk-spinner.d.ts +2 -1
- package/lib/types/elements/gtk-stack-page.d.ts +29 -0
- package/lib/types/elements/gtk-stack-sidebar.d.ts +2 -1
- package/lib/types/elements/gtk-stack-switcher.d.ts +2 -1
- package/lib/types/elements/gtk-stack.d.ts +13 -1
- package/lib/types/elements/gtk-switch.d.ts +2 -1
- package/lib/types/elements/gtk-text-view.d.ts +2 -1
- package/lib/types/elements/gtk-text.d.ts +2 -1
- package/lib/types/elements/gtk-tree-expander.d.ts +2 -1
- package/lib/types/elements/gtk-video.d.ts +2 -1
- package/lib/types/elements/gtk-viewport.d.ts +2 -1
- package/lib/types/elements/gtk-window-controls.d.ts +2 -1
- package/lib/types/elements/gtk-window-handle.d.ts +2 -1
- package/lib/types/elements/gtk-window.d.ts +18 -2
- package/lib/types/gobject-elements.d.ts +15 -0
- package/lib/types/gtksource/gtk-source-view.d.ts +2 -1
- package/lib/types/{icon-registry.spec.d.ts → icon-masks.spec.d.ts} +1 -1
- package/lib/types/icon-theme.d.ts +15 -35
- package/lib/types/index.d.ts +3 -4
- package/lib/types/learn6502-window.spec.d.ts +1 -0
- package/lib/types/namespace/adw.d.ts +1 -1
- package/lib/types/namespace/gdk.d.ts +1 -0
- package/lib/types/namespace/gio.d.ts +1 -0
- package/lib/types/namespace/glib.d.ts +2 -1
- package/lib/types/namespace/gtk.d.ts +2 -0
- package/lib/types/shared-tree-builder.d.ts +31 -0
- package/lib/types/signals.d.ts +5 -1
- package/lib/types/source-view/adw-source-view.d.ts +2 -1
- package/lib/types/styles.generated.d.ts +1 -1
- package/lib/types/widget-element.d.ts +25 -0
- package/lib/types/widget-map.spec.d.ts +1 -0
- package/lib/types/widget-mapping.d.ts +7 -0
- package/lib/types/widget-visible.spec.d.ts +1 -0
- package/lib/types/window-maximize.spec.d.ts +1 -0
- package/package.json +13 -12
- package/scss/_about_dialog.scss +46 -1
- package/scss/_bin.scss +6 -3
- package/scss/_checks.scss +5 -2
- package/scss/_icon.scss +3 -4
- package/scss/_labels.scss +2 -2
- package/scss/_overlay.scss +11 -1
- package/scss/_overlay_split_view.scss +10 -0
- package/scss/_reset.scss +1 -1
- package/scss/_scrolled_window.scss +15 -0
- package/scss/_stack.scss +8 -2
- package/scss/_toast.scss +13 -3
- package/scss/_widget.scss +5 -1
- package/scss/_window.scss +16 -0
- package/src/accessible.ts +29 -0
- package/src/adw-about-dialog.spec.ts +81 -12
- package/src/adw-action-rows.spec.ts +2 -2
- package/src/adw-alert-dialog.spec.ts +71 -5
- package/src/adw-bin.spec.ts +4 -3
- package/src/adw-button-content.spec.ts +1 -1
- package/src/adw-carousel.spec.ts +49 -1
- package/src/adw-header-bar.spec.ts +18 -0
- package/src/adw-toast-overlay.spec.ts +68 -24
- package/src/application.spec.ts +44 -0
- package/src/application.ts +13 -18
- package/src/capabilities.mjs +2 -3
- package/src/checks.spec.ts +51 -1
- package/src/child-slot.spec.ts +71 -0
- package/src/compute-expand.spec.ts +186 -0
- package/src/compute-expand.ts +134 -0
- package/src/construct-vectors.spec.ts +97 -7
- package/src/container-fill.spec.ts +70 -0
- package/src/elements/adw-about-dialog.ts +152 -9
- package/src/elements/adw-action-row.ts +2 -1
- package/src/elements/adw-alert-dialog.ts +177 -46
- package/src/elements/adw-application-window.ts +0 -3
- package/src/elements/adw-avatar.ts +2 -1
- package/src/elements/adw-banner.ts +2 -1
- package/src/elements/adw-bin.ts +2 -1
- package/src/elements/adw-bottom-sheet.ts +5 -4
- package/src/elements/adw-breakpoint-bin.ts +5 -1
- package/src/elements/adw-button-content.ts +2 -1
- package/src/elements/adw-button-row.ts +2 -1
- package/src/elements/adw-card.ts +2 -1
- package/src/elements/adw-carousel.ts +62 -3
- package/src/elements/adw-clamp-scrollable.ts +2 -1
- package/src/elements/adw-clamp.ts +2 -1
- package/src/elements/adw-combo-row.ts +15 -1
- package/src/elements/adw-data-grid.ts +2 -1
- package/src/elements/adw-dialog.ts +5 -2
- package/src/elements/adw-entry-row.ts +2 -1
- package/src/elements/adw-expander-row.ts +2 -1
- package/src/elements/adw-header-bar.ts +6 -1
- package/src/elements/adw-inline-view-switcher.ts +3 -2
- package/src/elements/adw-layout-slot.ts +2 -1
- package/src/elements/adw-multi-layout-view.ts +2 -1
- package/src/elements/adw-navigation-split-view.ts +2 -1
- package/src/elements/adw-navigation-view.ts +3 -2
- package/src/elements/adw-overlay-split-view.ts +2 -1
- package/src/elements/adw-preferences-dialog.ts +6 -4
- package/src/elements/adw-preferences-group.ts +2 -1
- package/src/elements/adw-preferences-row.ts +2 -1
- package/src/elements/adw-shortcut-label.ts +2 -1
- package/src/elements/adw-shortcuts-item.ts +2 -1
- package/src/elements/adw-shortcuts-section.ts +2 -1
- package/src/elements/adw-sidebar.ts +4 -3
- package/src/elements/adw-spin-row.ts +2 -1
- package/src/elements/adw-spinner.ts +2 -1
- package/src/elements/adw-split-button.ts +2 -1
- package/src/elements/adw-status-page.ts +2 -1
- package/src/elements/adw-switch-row.ts +10 -1
- package/src/elements/adw-tab-bar.ts +2 -1
- package/src/elements/adw-tab-button.ts +2 -1
- package/src/elements/adw-tab-overview.ts +2 -1
- package/src/elements/adw-tab-view.ts +3 -2
- package/src/elements/adw-toast-overlay.ts +37 -70
- package/src/elements/adw-toggle-group.ts +3 -2
- package/src/elements/adw-toolbar-view.ts +2 -1
- package/src/elements/adw-view-stack.ts +39 -1
- package/src/elements/adw-view-switcher-bar.ts +2 -1
- package/src/elements/adw-view-switcher-sidebar.ts +2 -1
- package/src/elements/adw-view-switcher.ts +3 -2
- package/src/elements/adw-window-features.ts +14 -2
- package/src/elements/adw-window-title.ts +2 -1
- package/src/elements/adw-wrap-box.ts +2 -1
- package/src/elements/checks.ts +85 -6
- package/src/elements/gtk-action-bar.ts +2 -1
- package/src/elements/gtk-application-window.ts +3 -8
- package/src/elements/gtk-aspect-frame.ts +2 -1
- package/src/elements/gtk-box.ts +56 -1
- package/src/elements/gtk-button.ts +10 -22
- package/src/elements/gtk-calendar.ts +2 -1
- package/src/elements/gtk-center-box.ts +2 -1
- package/src/elements/gtk-color-dialog-button.ts +2 -1
- package/src/elements/gtk-drag-icon.ts +6 -1
- package/src/elements/gtk-drawing-area.ts +2 -1
- package/src/elements/gtk-drop-down.ts +2 -1
- package/src/elements/gtk-editable-label.ts +2 -1
- package/src/elements/gtk-emoji-chooser.ts +5 -0
- package/src/elements/gtk-entry.ts +2 -1
- package/src/elements/gtk-expander.ts +2 -1
- package/src/elements/gtk-fixed.ts +2 -1
- package/src/elements/gtk-flow-box-child.ts +5 -2
- package/src/elements/gtk-flow-box.ts +2 -1
- package/src/elements/gtk-font-dialog-button.ts +2 -1
- package/src/elements/gtk-frame.ts +2 -1
- package/src/elements/gtk-gl-area.ts +2 -1
- package/src/elements/gtk-graphics-offload.ts +5 -2
- package/src/elements/gtk-grid.ts +2 -1
- package/src/elements/gtk-header-bar.ts +2 -1
- package/src/elements/gtk-image.ts +14 -15
- package/src/elements/gtk-inscription.ts +2 -1
- package/src/elements/gtk-label.ts +12 -5
- package/src/elements/gtk-level-bar.ts +2 -1
- package/src/elements/gtk-list-box-row.ts +5 -2
- package/src/elements/gtk-list-box.ts +2 -1
- package/src/elements/gtk-list-view.ts +2 -1
- package/src/elements/gtk-media-controls.ts +2 -1
- package/src/elements/gtk-menu-button.ts +2 -1
- package/src/elements/gtk-notebook.ts +2 -1
- package/src/elements/gtk-overlay.ts +7 -5
- package/src/elements/gtk-paned.ts +9 -2
- package/src/elements/gtk-picture.ts +2 -1
- package/src/elements/gtk-popover-bin.ts +5 -1
- package/src/elements/gtk-popover-menu-bar.ts +2 -1
- package/src/elements/gtk-popover-menu.ts +5 -0
- package/src/elements/gtk-popover.ts +14 -1
- package/src/elements/gtk-progress-bar.ts +2 -1
- package/src/elements/gtk-revealer.ts +2 -1
- package/src/elements/gtk-scale-button.ts +2 -1
- package/src/elements/gtk-scale.ts +2 -1
- package/src/elements/gtk-scrollbar.ts +2 -1
- package/src/elements/gtk-scrolled-window.ts +8 -5
- package/src/elements/gtk-search-bar.ts +7 -6
- package/src/elements/gtk-separator.ts +2 -1
- package/src/elements/gtk-spin-button.ts +2 -1
- package/src/elements/gtk-spinner.ts +2 -1
- package/src/elements/gtk-stack-page.ts +112 -0
- package/src/elements/gtk-stack-sidebar.ts +2 -1
- package/src/elements/gtk-stack-switcher.ts +2 -1
- package/src/elements/gtk-stack.ts +52 -6
- package/src/elements/gtk-switch.ts +2 -1
- package/src/elements/gtk-text-view.ts +2 -1
- package/src/elements/gtk-text.ts +2 -1
- package/src/elements/gtk-tree-expander.ts +5 -1
- package/src/elements/gtk-video.ts +2 -1
- package/src/elements/gtk-viewport.ts +6 -1
- package/src/elements/gtk-window-controls.ts +2 -1
- package/src/elements/gtk-window-handle.ts +6 -1
- package/src/elements/gtk-window.ts +57 -7
- package/src/gio.spec.ts +13 -3
- package/src/glib.spec.ts +9 -0
- package/src/gobject-elements.ts +44 -2
- package/src/gtk-label.spec.ts +39 -0
- package/src/gtk-scrolled-window.spec.ts +6 -6
- package/src/gtk-stack.spec.ts +170 -0
- package/src/gtk-value-doors.spec.ts +19 -0
- package/src/gtk-window.spec.ts +2 -2
- package/src/gtksource/gtk-source-view.ts +2 -1
- package/src/{icon-registry.spec.ts → icon-masks.spec.ts} +4 -100
- package/src/icon-theme.spec.ts +69 -124
- package/src/icon-theme.ts +29 -119
- package/src/index.ts +5 -9
- package/src/keyboard-operable.spec.ts +3 -3
- package/src/learn6502-window.spec.ts +113 -0
- package/src/namespace/adw.ts +1 -1
- package/src/namespace/gdk.ts +1 -0
- package/src/namespace/gio.ts +8 -0
- package/src/namespace/glib.ts +4 -0
- package/src/namespace/gtk.ts +2 -0
- package/src/shared-tree-builder.ts +131 -13
- package/src/shared-trees.spec.ts +15 -1
- package/src/signals.ts +11 -2
- package/src/slotted-children.spec.ts +24 -0
- package/src/slotted-children.ts +18 -2
- package/src/source-view/adw-source-view.ts +2 -1
- package/src/split-button.spec.ts +1 -1
- package/src/style-manager.spec.ts +13 -0
- package/src/style-manager.ts +6 -0
- package/src/styles.generated.ts +1 -1
- package/src/test.browser.mts +16 -2
- package/src/value-lists.spec.ts +3 -3
- package/src/widget-element.ts +75 -0
- package/src/widget-map.spec.ts +116 -0
- package/src/widget-mapping.ts +100 -0
- package/src/widget-visible.spec.ts +148 -0
- package/src/window-maximize.spec.ts +93 -0
- package/lib/types/icon-registry.d.ts +0 -37
- package/src/icon-registry.ts +0 -163
package/src/gtk-stack.spec.ts
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
import { describe, expect, it } from '@gjsify/unit';
|
|
8
8
|
|
|
9
9
|
import type { GtkStack } from './elements/gtk-stack.js';
|
|
10
|
+
import { pageChildOf } from './elements/gtk-stack-page.js';
|
|
11
|
+
import { mountSharedTree } from './shared-tree-builder.js';
|
|
10
12
|
|
|
11
13
|
interface Page {
|
|
12
14
|
name: string;
|
|
@@ -144,6 +146,66 @@ export const GtkStackTest = async () => {
|
|
|
144
146
|
host.remove();
|
|
145
147
|
});
|
|
146
148
|
|
|
149
|
+
await it('a descendant toggling hidden keeps the selection', async () => {
|
|
150
|
+
// gtkstack.c:1617-1633 listens to the PAGE's own visibility, never to what is
|
|
151
|
+
// nested inside it (an `adw-view-stack` showing and hiding its own pages).
|
|
152
|
+
const { el, host } = mount([
|
|
153
|
+
{ name: 'single', title: 'Single' },
|
|
154
|
+
{ name: 'three', title: 'Three' },
|
|
155
|
+
]);
|
|
156
|
+
const nested = document.createElement('span');
|
|
157
|
+
el.children[0]!.appendChild(nested);
|
|
158
|
+
el.setVisibleChildName('three');
|
|
159
|
+
nested.setAttribute('hidden', '');
|
|
160
|
+
await settle();
|
|
161
|
+
nested.removeAttribute('hidden');
|
|
162
|
+
await settle();
|
|
163
|
+
expect(el.visibleChildName).toBe('three');
|
|
164
|
+
expect(marks(el)).toStrictEqual(['single', 'three:visible']);
|
|
165
|
+
host.remove();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
await it('hiding a page that is not visible keeps the selection', async () => {
|
|
169
|
+
const { el, host } = mount([
|
|
170
|
+
{ name: 'a', title: 'Alpha' },
|
|
171
|
+
{ name: 'b', title: 'Beta' },
|
|
172
|
+
{ name: 'c', title: 'Gamma' },
|
|
173
|
+
]);
|
|
174
|
+
el.setVisibleChildName('c');
|
|
175
|
+
(el.children[1] as HTMLElement).setAttribute('hidden', '');
|
|
176
|
+
await settle();
|
|
177
|
+
expect(el.visibleChildName).toBe('c');
|
|
178
|
+
host.remove();
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
await it('hiding the visible page after a selection falls back to the first visible', async () => {
|
|
182
|
+
const { el, host } = mount([
|
|
183
|
+
{ name: 'a', title: 'Alpha' },
|
|
184
|
+
{ name: 'b', title: 'Beta' },
|
|
185
|
+
{ name: 'c', title: 'Gamma' },
|
|
186
|
+
]);
|
|
187
|
+
el.setVisibleChildName('c');
|
|
188
|
+
(el.children[0] as HTMLElement).setAttribute('hidden', '');
|
|
189
|
+
(el.children[2] as HTMLElement).setAttribute('hidden', '');
|
|
190
|
+
await settle();
|
|
191
|
+
expect(el.visibleChildName).toBe('b');
|
|
192
|
+
host.remove();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
await it('a descendant name change dispatches no page-updated', async () => {
|
|
196
|
+
const { el, host } = mount([{ name: 'a', title: 'Alpha' }]);
|
|
197
|
+
const nested = document.createElement('span');
|
|
198
|
+
el.children[0]!.appendChild(nested);
|
|
199
|
+
await settle();
|
|
200
|
+
const events: string[] = [];
|
|
201
|
+
el.addEventListener('page-updated', () => events.push('updated'));
|
|
202
|
+
nested.setAttribute('name', 'inner');
|
|
203
|
+
await settle();
|
|
204
|
+
expect(events).toStrictEqual([]);
|
|
205
|
+
expect(el.visibleChildName).toBe('a');
|
|
206
|
+
host.remove();
|
|
207
|
+
});
|
|
208
|
+
|
|
147
209
|
await it('re-selecting the visible page is not a change', () => {
|
|
148
210
|
// gtkstack.c:1452-1453 — no notify, no transition.
|
|
149
211
|
const { el, host } = mount([
|
|
@@ -429,4 +491,112 @@ export const GtkStackTest = async () => {
|
|
|
429
491
|
host.remove();
|
|
430
492
|
});
|
|
431
493
|
});
|
|
494
|
+
|
|
495
|
+
await describe('<gtk-stack> adopts a <gtk-stack-page> record', async () => {
|
|
496
|
+
const record = (attrs: Record<string, string>, body = 'page'): HTMLElement => {
|
|
497
|
+
const page = document.createElement('gtk-stack-page');
|
|
498
|
+
for (const [name, value] of Object.entries(attrs)) page.setAttribute(name, value);
|
|
499
|
+
const child = document.createElement('div');
|
|
500
|
+
child.setAttribute('slot', 'child');
|
|
501
|
+
child.textContent = body;
|
|
502
|
+
page.appendChild(child);
|
|
503
|
+
return page;
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
await it('puts the child where the record was, with its properties as attributes', () => {
|
|
507
|
+
const host = document.createElement('div');
|
|
508
|
+
document.body.appendChild(host);
|
|
509
|
+
const el = document.createElement('gtk-stack') as GtkStack;
|
|
510
|
+
el.appendChild(
|
|
511
|
+
record({
|
|
512
|
+
name: 'a',
|
|
513
|
+
title: 'Alpha',
|
|
514
|
+
'icon-name': 'go-home',
|
|
515
|
+
'needs-attention': '',
|
|
516
|
+
'use-underline': '',
|
|
517
|
+
}),
|
|
518
|
+
);
|
|
519
|
+
el.appendChild(record({ name: 'b' }, 'beta'));
|
|
520
|
+
host.appendChild(el);
|
|
521
|
+
expect(el.querySelector('gtk-stack-page')).toBe(null);
|
|
522
|
+
expect(marks(el)).toStrictEqual(['a:visible', 'b']);
|
|
523
|
+
const [page] = el.pages;
|
|
524
|
+
expect(page!.title).toBe('Alpha');
|
|
525
|
+
expect(page!.iconName).toBe('go-home');
|
|
526
|
+
expect(page!.needsAttention).toBe(true);
|
|
527
|
+
expect(page!.useUnderline).toBe(true);
|
|
528
|
+
expect(page!.child.hasAttribute('slot')).toBe(false);
|
|
529
|
+
expect(el.getChildByName('b')!.textContent).toBe('beta');
|
|
530
|
+
host.remove();
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
await it('reads a hidden record as GtkStackPage:visible = FALSE', () => {
|
|
534
|
+
const host = document.createElement('div');
|
|
535
|
+
document.body.appendChild(host);
|
|
536
|
+
const el = document.createElement('gtk-stack') as GtkStack;
|
|
537
|
+
const hidden = record({ name: 'a' });
|
|
538
|
+
(hidden as unknown as { visible: boolean }).visible = false;
|
|
539
|
+
el.appendChild(hidden);
|
|
540
|
+
el.appendChild(record({ name: 'b' }));
|
|
541
|
+
host.appendChild(el);
|
|
542
|
+
expect(el.pages.map((page) => page.visible)).toStrictEqual([false, true]);
|
|
543
|
+
expect(el.visibleChildName).toBe('b');
|
|
544
|
+
host.remove();
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
await it('adopts a record appended after connect, counted once', async () => {
|
|
548
|
+
const { el, host } = mount([{ name: 'a' }]);
|
|
549
|
+
const events: unknown[] = [];
|
|
550
|
+
el.addEventListener('items-changed', (e) => events.push((e as CustomEvent).detail));
|
|
551
|
+
el.appendChild(record({ name: 'b' }));
|
|
552
|
+
await settle();
|
|
553
|
+
await settle();
|
|
554
|
+
expect(marks(el)).toStrictEqual(['a:visible', 'b']);
|
|
555
|
+
expect(events).toStrictEqual([{ position: 1, removed: 0, added: 1 }]);
|
|
556
|
+
host.remove();
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
await it('takes a bare child as the page, and refuses a record with two', () => {
|
|
560
|
+
const bare = document.createElement('gtk-stack-page');
|
|
561
|
+
const child = document.createElement('div');
|
|
562
|
+
bare.appendChild(child);
|
|
563
|
+
expect(pageChildOf(bare)).toBe(child);
|
|
564
|
+
bare.appendChild(document.createElement('div'));
|
|
565
|
+
expect(() => pageChildOf(bare)).toThrow('has one `child`');
|
|
566
|
+
expect(pageChildOf(document.createElement('gtk-stack-page'))).toBe(null);
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
await it('builds `Stack { StackPage { name; child: … } }` from a shared tree', () => {
|
|
570
|
+
const { root, unmount } = mountSharedTree({
|
|
571
|
+
tag: 'GtkStack',
|
|
572
|
+
id: 'layoutHost',
|
|
573
|
+
children: [
|
|
574
|
+
{
|
|
575
|
+
tag: 'GtkStackPage',
|
|
576
|
+
id: 'singlePage',
|
|
577
|
+
props: { name: 'single' },
|
|
578
|
+
children: [{ tag: 'AdwBin', slot: 'child', id: 'singleBin' }],
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
tag: 'GtkStackPage',
|
|
582
|
+
id: 'threePage',
|
|
583
|
+
props: { name: 'three', title: 'Three' },
|
|
584
|
+
children: [{ tag: 'AdwBin', slot: 'child', id: 'threeBin' }],
|
|
585
|
+
},
|
|
586
|
+
],
|
|
587
|
+
});
|
|
588
|
+
try {
|
|
589
|
+
const stack = root as GtkStack;
|
|
590
|
+
expect(stack.pages.map((page) => page.child.id)).toStrictEqual(['singleBin', 'threeBin']);
|
|
591
|
+
// The first page added is the visible one (gtkstack.c:1773-1775); a breakpoint
|
|
592
|
+
// setter selects another by the name its record carried.
|
|
593
|
+
expect(stack.visibleChild!.id).toBe('singleBin');
|
|
594
|
+
expect(stack.setVisibleChildName('three')).toBe(true);
|
|
595
|
+
expect(stack.visibleChild!.id).toBe('threeBin');
|
|
596
|
+
expect(stack.getPage(stack.visibleChild!)!.title).toBe('Three');
|
|
597
|
+
} finally {
|
|
598
|
+
unmount();
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
});
|
|
432
602
|
};
|
|
@@ -20,8 +20,15 @@
|
|
|
20
20
|
import { describe, it, expect } from '@gjsify/unit';
|
|
21
21
|
|
|
22
22
|
import { GtkAdjustment, GtkStringList } from '@gjsify/adwaita-core';
|
|
23
|
+
import {
|
|
24
|
+
ROW_ACCESSOR_VECTORS,
|
|
25
|
+
driveRowAccessorVectors,
|
|
26
|
+
type ComboRowLike,
|
|
27
|
+
type SwitchRowLike,
|
|
28
|
+
} from '@gjsify/adwaita-core/conformance';
|
|
23
29
|
|
|
24
30
|
import type { AdwComboRow } from './elements/adw-combo-row.js';
|
|
31
|
+
import type { AdwSwitchRow } from './elements/adw-switch-row.js';
|
|
25
32
|
import type { AdwSpinRow } from './elements/adw-spin-row.js';
|
|
26
33
|
import type { GtkDropDown } from './elements/gtk-drop-down.js';
|
|
27
34
|
|
|
@@ -101,4 +108,16 @@ export const GtkValueDoorsTest = async () => {
|
|
|
101
108
|
expect(row.value).toBe(16);
|
|
102
109
|
});
|
|
103
110
|
});
|
|
111
|
+
|
|
112
|
+
await driveRowAccessorVectors(
|
|
113
|
+
{
|
|
114
|
+
name: 'adwaita-web',
|
|
115
|
+
isOracle: false,
|
|
116
|
+
makeComboRow: () => mount<AdwComboRow>('adw-combo-row') as unknown as ComboRowLike,
|
|
117
|
+
makeSwitchRow: () => mount<AdwSwitchRow>('adw-switch-row') as unknown as SwitchRowLike,
|
|
118
|
+
StringList: GtkStringList,
|
|
119
|
+
},
|
|
120
|
+
{ describe, it, expect },
|
|
121
|
+
ROW_ACCESSOR_VECTORS,
|
|
122
|
+
);
|
|
104
123
|
};
|
package/src/gtk-window.spec.ts
CHANGED
|
@@ -310,11 +310,11 @@ export const GtkWindowTest = async () => {
|
|
|
310
310
|
const { el, host } = mount();
|
|
311
311
|
let message = '';
|
|
312
312
|
try {
|
|
313
|
-
el.connect('
|
|
313
|
+
el.connect('toggled', () => {});
|
|
314
314
|
} catch (error) {
|
|
315
315
|
message = (error as Error).message;
|
|
316
316
|
}
|
|
317
|
-
expect(message.includes("'
|
|
317
|
+
expect(message.includes("'toggled'")).toBe(true);
|
|
318
318
|
host.remove();
|
|
319
319
|
});
|
|
320
320
|
|
|
@@ -20,6 +20,7 @@ import type { Buffer, Gutter } from '@gjsify/gtksource-core';
|
|
|
20
20
|
import { EditorSession, GutterSet, STOP_EMISSION, toBoolean, toNumber } from '@gjsify/gtksource-core';
|
|
21
21
|
|
|
22
22
|
import { WebEditorDriver } from './web-editor-driver.js';
|
|
23
|
+
import { WidgetElement } from '../widget-element.js';
|
|
23
24
|
|
|
24
25
|
const STYLE_ID = 'gjsify-gtk-source-view-style';
|
|
25
26
|
|
|
@@ -130,7 +131,7 @@ const OBSERVED_ATTRIBUTES = [
|
|
|
130
131
|
'bottom-margin',
|
|
131
132
|
];
|
|
132
133
|
|
|
133
|
-
export class GtkSourceView extends
|
|
134
|
+
export class GtkSourceView extends WidgetElement {
|
|
134
135
|
static get observedAttributes(): string[] {
|
|
135
136
|
return OBSERVED_ATTRIBUTES;
|
|
136
137
|
}
|
|
@@ -14,17 +14,12 @@
|
|
|
14
14
|
// that was never given draws nothing at all.
|
|
15
15
|
import { describe, expect, it } from '@gjsify/unit';
|
|
16
16
|
|
|
17
|
-
import { isIconAvailable
|
|
17
|
+
import { isIconAvailable } from './icon-theme.js';
|
|
18
18
|
import type { GtkImage } from './elements/gtk-image.js';
|
|
19
19
|
|
|
20
20
|
/** A name no compiled entry can collide with, for the "not shipped" arm. */
|
|
21
21
|
const ABSENT = 'gjsify-registry-probe';
|
|
22
22
|
|
|
23
|
-
/** An Adwaita symbolic SVG, small and distinctive — a filled 8px square in the 16px grid. */
|
|
24
|
-
const PROBE_SVG = `<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
|
|
25
|
-
<path d="m 4 4 h 8 v 8 h -8 z m 0 0" fill="currentColor"/>
|
|
26
|
-
</svg>`;
|
|
27
|
-
|
|
28
23
|
function mount(iconName: string | null): { el: GtkImage; host: HTMLElement } {
|
|
29
24
|
const host = document.createElement('div');
|
|
30
25
|
document.body.appendChild(host);
|
|
@@ -55,7 +50,7 @@ export function fallbackMask(): string {
|
|
|
55
50
|
return getComputedStyle(document.documentElement).getPropertyValue('--icon-image-missing').trim();
|
|
56
51
|
}
|
|
57
52
|
|
|
58
|
-
export const
|
|
53
|
+
export const AdwIconMasksTest = async () => {
|
|
59
54
|
await describe('<gtk-image> resolves a name to a real mask', async () => {
|
|
60
55
|
await it('a compiled name draws its OWN glyph, not the fallback', () => {
|
|
61
56
|
const { el, host } = mount('go-next');
|
|
@@ -136,8 +131,8 @@ export const AdwIconRegistryTest = async () => {
|
|
|
136
131
|
});
|
|
137
132
|
});
|
|
138
133
|
|
|
139
|
-
await describe('
|
|
140
|
-
await it('
|
|
134
|
+
await describe('isIconAvailable', async () => {
|
|
135
|
+
await it('answers for the compiled set and nothing else', () => {
|
|
141
136
|
expect(isIconAvailable(ABSENT)).toBe(false);
|
|
142
137
|
// …and a compiled one as available, so the check is not answering `false` to
|
|
143
138
|
// everything. `image-missing` is the case a fallback-comparison would get wrong.
|
|
@@ -145,96 +140,5 @@ export const AdwIconRegistryTest = async () => {
|
|
|
145
140
|
expect(isIconAvailable('image-missing')).toBe(true);
|
|
146
141
|
expect(isIconAvailable('')).toBe(false);
|
|
147
142
|
});
|
|
148
|
-
|
|
149
|
-
await it('makes the name resolve, on an element that is ALREADY mounted', () => {
|
|
150
|
-
const { el, host } = mount(ABSENT);
|
|
151
|
-
const before = maskOf(el);
|
|
152
|
-
expect(before).toBe(fallbackMask());
|
|
153
|
-
|
|
154
|
-
registerIcon(ABSENT, PROBE_SVG);
|
|
155
|
-
|
|
156
|
-
const after = maskOf(el);
|
|
157
|
-
expect(after).not.toBe(before);
|
|
158
|
-
expect(after).not.toBe(fallbackMask());
|
|
159
|
-
// The glyph really is the SVG that was handed over: `toDataUri` percent-encodes
|
|
160
|
-
// it, so the path data survives as `m%204%204`.
|
|
161
|
-
expect(after.includes('m%204%204')).toBe(true);
|
|
162
|
-
expect(isIconAvailable(ABSENT)).toBe(true);
|
|
163
|
-
host.remove();
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
await it('serves an element mounted AFTER the registration too', () => {
|
|
167
|
-
const { el, host } = mount(`${ABSENT}-symbolic`);
|
|
168
|
-
// The `-symbolic` suffix is stripped on both sides, so a consumer may spell the
|
|
169
|
-
// name either way at either end.
|
|
170
|
-
expect(el.resolvedIconName).toBe(ABSENT);
|
|
171
|
-
expect(maskOf(el).includes('m%204%204')).toBe(true);
|
|
172
|
-
host.remove();
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
await it('re-registering REPLACES the glyph without a second rule', () => {
|
|
176
|
-
const sheet = (document.getElementById('adwaita-web-icon-registry') as HTMLStyleElement).sheet;
|
|
177
|
-
const rulesBefore = (sheet as CSSStyleSheet).cssRules.length;
|
|
178
|
-
|
|
179
|
-
registerIcon(ABSENT, PROBE_SVG.replace('m 4 4 h 8 v 8 h -8 z', 'm 2 2 h 12 v 12 h -12 z'));
|
|
180
|
-
|
|
181
|
-
const { el, host } = mount(ABSENT);
|
|
182
|
-
expect(maskOf(el).includes('m%202%202')).toBe(true);
|
|
183
|
-
expect((sheet as CSSStyleSheet).cssRules.length).toBe(rulesBefore);
|
|
184
|
-
host.remove();
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
await it('throws on a name that could never be one CSS class', () => {
|
|
188
|
-
// Silently registering nothing is the exact failure this area exists to end, and
|
|
189
|
-
// unlike a render this is an explicit call with a wrong argument.
|
|
190
|
-
expect(() => registerIcon('org.gnome.Builder', PROBE_SVG)).toThrow();
|
|
191
|
-
expect(() => registerIcon('a b', PROBE_SVG)).toThrow();
|
|
192
|
-
expect(() => registerIcon('', PROBE_SVG)).toThrow();
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
await it('throws on a payload that is not SVG source, and registers nothing', () => {
|
|
196
|
-
// The NAME was checked from the start; the payload was not, and a wrong payload
|
|
197
|
-
// is worse than no registration at all: `toDataUri` percent-encodes anything, so
|
|
198
|
-
// the mask comes out well-formed and masks NOTHING, the registered class beats
|
|
199
|
-
// `:where(.adw-icon)` and switches this PR's fallback off, and `isIconAvailable`
|
|
200
|
-
// answers `true`. Measured in Firefox before the guard: `'not an svg at all'`
|
|
201
|
-
// gave `url("data:image/svg+xml,not%20an%20svg%20at%20all")` on a box painted 0 %,
|
|
202
|
-
// where the unregistered control painted the 30 % image-missing glyph.
|
|
203
|
-
const REJECTED = 'gjsify-registry-payload-probe';
|
|
204
|
-
expect(() => registerIcon(REJECTED, 'not an svg at all')).toThrow();
|
|
205
|
-
expect(() => registerIcon(REJECTED, '')).toThrow();
|
|
206
|
-
// The likeliest wrong argument of all: what the custom property HOLDS, handed
|
|
207
|
-
// over instead of what it was made from.
|
|
208
|
-
expect(() => registerIcon(REJECTED, 'url("data:image/svg+xml,%3Csvg%3E%3C/svg%3E")')).toThrow();
|
|
209
|
-
expect(isIconAvailable(REJECTED)).toBe(false);
|
|
210
|
-
|
|
211
|
-
const { el, host } = mount(REJECTED);
|
|
212
|
-
expect(maskOf(el)).toBe(fallbackMask());
|
|
213
|
-
host.remove();
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
await it('rebuilds its rules after the <style> element is taken away', () => {
|
|
217
|
-
// What an SPA head swap or an Astro view transition does. The record of inserted
|
|
218
|
-
// rules is module-level and outlives the element it describes, so the early
|
|
219
|
-
// return above used to skip the insert forever: the custom property was re-set
|
|
220
|
-
// and the rule that consumes it never came back.
|
|
221
|
-
const LOST = 'gjsify-registry-sheet-probe';
|
|
222
|
-
registerIcon(LOST, PROBE_SVG);
|
|
223
|
-
document.getElementById('adwaita-web-icon-registry')?.remove();
|
|
224
|
-
|
|
225
|
-
registerIcon(LOST, PROBE_SVG);
|
|
226
|
-
|
|
227
|
-
expect(document.getElementById('adwaita-web-icon-registry')).not.toBe(null);
|
|
228
|
-
const { el, host } = mount(LOST);
|
|
229
|
-
expect(maskOf(el).includes('m%204%204')).toBe(true);
|
|
230
|
-
host.remove();
|
|
231
|
-
|
|
232
|
-
// …and the names registered BEFORE the swap are on the rebuilt sheet too. Their
|
|
233
|
-
// custom properties survived on the document element, so re-issuing only the
|
|
234
|
-
// one name being registered would leave every earlier icon on the fallback.
|
|
235
|
-
const { el: earlier, host: earlierHost } = mount(ABSENT);
|
|
236
|
-
expect(maskOf(earlier)).not.toBe(fallbackMask());
|
|
237
|
-
earlierHost.remove();
|
|
238
|
-
});
|
|
239
143
|
});
|
|
240
144
|
};
|
package/src/icon-theme.spec.ts
CHANGED
|
@@ -1,30 +1,38 @@
|
|
|
1
1
|
// The colour half of the icon theme, measured through `getComputedStyle` like
|
|
2
|
-
// `icon-
|
|
2
|
+
// `icon-masks.spec.ts` measures the symbolic half: a class on the node proves nothing
|
|
3
3
|
// about what it paints.
|
|
4
4
|
//
|
|
5
5
|
// The order under test is GLib's (`g_themed_icon_update_names`, which `GtkImage`'s lookup
|
|
6
6
|
// goes through): `X` tries [X, X-symbolic], `X-symbolic` tries [X-symbolic, X], and a name
|
|
7
7
|
// neither answers draws `image-missing`. Over the names the order is gtkicontheme.c's: the
|
|
8
|
-
// current theme (the stylesheet's glyphs) before hicolor, where
|
|
9
|
-
//
|
|
10
|
-
//
|
|
8
|
+
// current theme (the stylesheet's glyphs) before hicolor, where an app's resource files sit.
|
|
9
|
+
// Colour icons come from the shared GResource fixture, on the theme's resource path as
|
|
10
|
+
// `GtkApplication` adds `<resource-base-path>/icons/` (ADR 0116 § 4).
|
|
11
|
+
import { ICON_FIXTURE_PATH, gioResourceFixtures } from '@gjsify/adwaita-core/conformance';
|
|
11
12
|
import { describe, expect, it } from '@gjsify/unit';
|
|
12
13
|
|
|
13
14
|
import { COLOR_ICON_CLASS, type GtkImage } from './elements/gtk-image.js';
|
|
14
|
-
import { fallbackMask, maskOf } from './icon-
|
|
15
|
-
import { isIconAvailable
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
15
|
+
import { fallbackMask, maskOf } from './icon-masks.spec.js';
|
|
16
|
+
import { isIconAvailable } from './icon-theme.js';
|
|
17
|
+
import { Gio, Gtk } from './index.js';
|
|
18
|
+
|
|
19
|
+
const theme = Gtk.IconTheme.get_for_display(null);
|
|
20
|
+
|
|
21
|
+
/** Runs `body` with the fixture's icons on the theme's resource path. */
|
|
22
|
+
async function withIcons(body: () => void): Promise<void> {
|
|
23
|
+
const resource = Gio.Resource.new_from_data(gioResourceFixtures().icons);
|
|
24
|
+
Gio.resources_register(resource);
|
|
25
|
+
const before = theme.get_resource_path();
|
|
26
|
+
theme.add_resource_path(ICON_FIXTURE_PATH);
|
|
27
|
+
// `changed` is deferred: let it drop the previous scan's URLs first.
|
|
28
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
29
|
+
try {
|
|
30
|
+
body();
|
|
31
|
+
} finally {
|
|
32
|
+
theme.set_resource_path(before);
|
|
33
|
+
Gio.resources_unregister(resource);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
28
36
|
|
|
29
37
|
function mount(iconName: string): { el: GtkImage; host: HTMLElement } {
|
|
30
38
|
const host = document.createElement('div');
|
|
@@ -40,7 +48,7 @@ function maskClasses(el: HTMLElement): string[] {
|
|
|
40
48
|
return [...el.classList].filter((c) => c.startsWith('adw-icon--'));
|
|
41
49
|
}
|
|
42
50
|
|
|
43
|
-
/** True when `el` paints
|
|
51
|
+
/** True when `el` paints a resource image as-is and nothing masked. */
|
|
44
52
|
function drawsInColor(el: HTMLElement): boolean {
|
|
45
53
|
const style = getComputedStyle(el);
|
|
46
54
|
return (
|
|
@@ -48,66 +56,41 @@ function drawsInColor(el: HTMLElement): boolean {
|
|
|
48
56
|
maskClasses(el).length === 0 &&
|
|
49
57
|
style.maskImage === 'none' &&
|
|
50
58
|
style.backgroundColor === 'rgba(0, 0, 0, 0)' &&
|
|
51
|
-
|
|
52
|
-
style.backgroundImage.includes('%23e01b24')
|
|
59
|
+
style.backgroundImage.startsWith('url("blob:')
|
|
53
60
|
);
|
|
54
61
|
}
|
|
55
62
|
|
|
56
63
|
export const AdwIconThemeTest = async () => {
|
|
57
|
-
await describe('
|
|
58
|
-
await it('
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
host.remove();
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
await it('an already-mounted element redraws when the registration lands', () => {
|
|
69
|
-
const APP_ID = 'org.gjsify.LateColorProbe';
|
|
70
|
-
const { el, host } = mount(APP_ID);
|
|
71
|
-
// Before: what GTK draws for a name its theme does not have.
|
|
72
|
-
expect(maskOf(el)).toBe(fallbackMask());
|
|
73
|
-
|
|
74
|
-
registerColorIcon(APP_ID, COLOR_SVG);
|
|
75
|
-
expect(drawsInColor(el)).toBe(true);
|
|
76
|
-
host.remove();
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
await it("AdwAboutDialog's application-icon draws in colour", () => {
|
|
80
|
-
const APP_ID = 'org.gjsify.AboutColorProbe';
|
|
81
|
-
registerColorIcon(APP_ID, COLOR_SVG);
|
|
82
|
-
|
|
83
|
-
const host = document.createElement('div');
|
|
84
|
-
document.body.appendChild(host);
|
|
85
|
-
const dialog = document.createElement('adw-about-dialog');
|
|
86
|
-
dialog.setAttribute('application-icon', APP_ID);
|
|
87
|
-
host.appendChild(dialog);
|
|
88
|
-
|
|
89
|
-
const icon = dialog.querySelector('.adw-about-dialog-icon') as HTMLElement;
|
|
90
|
-
expect(drawsInColor(icon)).toBe(true);
|
|
91
|
-
// The 96px box, and NOT a solid square under the image: the about dialog used to
|
|
92
|
-
// force `background-color: currentColor` on it.
|
|
93
|
-
expect(getComputedStyle(icon).width).toBe('96px');
|
|
94
|
-
host.remove();
|
|
64
|
+
await describe('a full-colour resource icon draws as-is', async () => {
|
|
65
|
+
await it('draws its image, unmasked and unfilled', async () => {
|
|
66
|
+
await withIcons(() => {
|
|
67
|
+
const { el, host } = mount('flat');
|
|
68
|
+
expect(drawsInColor(el)).toBe(true);
|
|
69
|
+
expect(isIconAvailable('flat')).toBe(true);
|
|
70
|
+
host.remove();
|
|
71
|
+
});
|
|
95
72
|
});
|
|
96
73
|
|
|
97
|
-
await it('
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
74
|
+
await it("AdwAboutDialog's application-icon draws in colour", async () => {
|
|
75
|
+
await withIcons(() => {
|
|
76
|
+
const host = document.createElement('div');
|
|
77
|
+
document.body.appendChild(host);
|
|
78
|
+
const dialog = document.createElement('adw-about-dialog');
|
|
79
|
+
dialog.setAttribute('application-icon', 'flat');
|
|
80
|
+
host.appendChild(dialog);
|
|
81
|
+
|
|
82
|
+
const icon = dialog.querySelector('.adw-about-dialog-icon') as HTMLElement;
|
|
83
|
+
expect(drawsInColor(icon)).toBe(true);
|
|
84
|
+
// The 96px box, and NOT a solid square under the image: the about dialog used to
|
|
85
|
+
// force `background-color: currentColor` on it.
|
|
86
|
+
expect(getComputedStyle(icon).width).toBe('96px');
|
|
87
|
+
host.remove();
|
|
88
|
+
});
|
|
106
89
|
});
|
|
107
90
|
});
|
|
108
91
|
|
|
109
92
|
await describe('the lookup order is GThemedIcon’s', async () => {
|
|
110
|
-
await it('a symbolic icon still masks — a compiled one with no
|
|
93
|
+
await it('a symbolic icon still masks — a compiled one with no resource', () => {
|
|
111
94
|
const { el, host } = mount('go-next-symbolic');
|
|
112
95
|
expect(el.classList.contains(COLOR_ICON_CLASS)).toBe(false);
|
|
113
96
|
expect(maskClasses(el)).toStrictEqual(['adw-icon--go-next']);
|
|
@@ -116,41 +99,28 @@ export const AdwIconThemeTest = async () => {
|
|
|
116
99
|
host.remove();
|
|
117
100
|
});
|
|
118
101
|
|
|
119
|
-
await it("the theme's X-symbolic answers X
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
expect(maskOf(plain.el).includes('m%203%203')).toBe(true);
|
|
129
|
-
plain.host.remove();
|
|
130
|
-
|
|
131
|
-
const symbolic = mount(`${NAME}-symbolic`);
|
|
132
|
-
expect(symbolic.el.classList.contains(COLOR_ICON_CLASS)).toBe(false);
|
|
133
|
-
expect(maskOf(symbolic.el).includes('m%203%203')).toBe(true);
|
|
134
|
-
expect(getComputedStyle(symbolic.el).backgroundImage).toBe('none');
|
|
135
|
-
symbolic.host.remove();
|
|
102
|
+
await it("the theme's X-symbolic answers X before a resource's colour X, as on GTK", async () => {
|
|
103
|
+
// The fixture ships a colour `16x16/actions/go-next.png`; gtkicontheme.c
|
|
104
|
+
// `real_choose_icon` goes theme outer, name inner, and the file is hicolor's.
|
|
105
|
+
await withIcons(() => {
|
|
106
|
+
const { el, host } = mount('go-next');
|
|
107
|
+
expect(el.classList.contains(COLOR_ICON_CLASS)).toBe(false);
|
|
108
|
+
expect(maskClasses(el)).toStrictEqual(['adw-icon--go-next']);
|
|
109
|
+
host.remove();
|
|
110
|
+
});
|
|
136
111
|
});
|
|
137
112
|
|
|
138
|
-
await it('X-symbolic falls back to the colour X,
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
registerIcon(NAME, SYMBOLIC_SVG);
|
|
147
|
-
expect(el.classList.contains(COLOR_ICON_CLASS)).toBe(false);
|
|
148
|
-
expect(maskOf(el).includes('m%203%203')).toBe(true);
|
|
149
|
-
host.remove();
|
|
113
|
+
await it('X-symbolic falls back to the colour X', async () => {
|
|
114
|
+
await withIcons(() => {
|
|
115
|
+
const { el, host } = mount('flat-symbolic');
|
|
116
|
+
expect(drawsInColor(el)).toBe(true);
|
|
117
|
+
expect(isIconAvailable('flat-symbolic')).toBe(true);
|
|
118
|
+
host.remove();
|
|
119
|
+
});
|
|
150
120
|
});
|
|
151
121
|
|
|
152
122
|
await it('an unknown name draws image-missing', () => {
|
|
153
|
-
for (const unknown of ['org.gjsify.
|
|
123
|
+
for (const unknown of ['org.gjsify.NeverShipped', 'gjsify-theme-never-shipped', 'flat']) {
|
|
154
124
|
const { el, host } = mount(unknown);
|
|
155
125
|
expect(el.classList.contains(COLOR_ICON_CLASS)).toBe(false);
|
|
156
126
|
expect(maskOf(el)).toBe(fallbackMask());
|
|
@@ -159,29 +129,4 @@ export const AdwIconThemeTest = async () => {
|
|
|
159
129
|
}
|
|
160
130
|
});
|
|
161
131
|
});
|
|
162
|
-
|
|
163
|
-
await describe('registerColorIcon rejects what it cannot draw faithfully', async () => {
|
|
164
|
-
await it('throws on a name that is empty, spaced, or symbolic', () => {
|
|
165
|
-
expect(() => registerColorIcon('', COLOR_SVG)).toThrow();
|
|
166
|
-
expect(() => registerColorIcon('a b', COLOR_SVG)).toThrow();
|
|
167
|
-
// The symbolic half has its own door; GTK's theme treats all three suffixes as
|
|
168
|
-
// symbolic files.
|
|
169
|
-
expect(() => registerColorIcon('gjsify-probe-symbolic', COLOR_SVG)).toThrow();
|
|
170
|
-
expect(() => registerColorIcon('gjsify-probe-symbolic-ltr', COLOR_SVG)).toThrow();
|
|
171
|
-
expect(() => registerColorIcon('gjsify-probe-symbolic-rtl', COLOR_SVG)).toThrow();
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
await it('throws on a source that is not SVG or an image URL, and registers nothing', () => {
|
|
175
|
-
const REJECTED = 'org.gjsify.RejectedColorProbe';
|
|
176
|
-
expect(() => registerColorIcon(REJECTED, '')).toThrow();
|
|
177
|
-
expect(() => registerColorIcon(REJECTED, '<p>not svg</p>')).toThrow();
|
|
178
|
-
expect(() => registerColorIcon(REJECTED, 'javascript:alert(1)')).toThrow();
|
|
179
|
-
expect(() => registerColorIcon(REJECTED, 'data:text/html,<svg></svg>')).toThrow();
|
|
180
|
-
expect(isIconAvailable(REJECTED)).toBe(false);
|
|
181
|
-
|
|
182
|
-
const { el, host } = mount(REJECTED);
|
|
183
|
-
expect(maskOf(el)).toBe(fallbackMask());
|
|
184
|
-
host.remove();
|
|
185
|
-
});
|
|
186
|
-
});
|
|
187
132
|
};
|