Skip to content

Commit ceac326

Browse files
committed
Merge branch 'next' into feat/query-anchor
2 parents 98cdba5 + 14c0c1a commit ceac326

File tree

6 files changed

+226
-10
lines changed

6 files changed

+226
-10
lines changed

CHANGELOG.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,7 @@ Please note after `1.0` Semver will be followed using normal protocols.
99
# Version 0.17.0 - xx.xx.xxxx
1010

1111
## Major Features
12-
* **Anchor/Positioning** - Added new `anchor` behavior that allows you to position elements relative to other elements using `css anchor`
13-
14-
## Bugs
15-
* **Query Plugins** - Fixed issue where using non clonables as settings like query collections, or custom classes wouldn't work as expected. This was related to the default behavior of deepExtend and clone (see breaking changes).
16-
* **Query** - Fixed bug in `is` where it would return true for non-existent selectors
17-
18-
## Features
19-
* **Utils** - Clone now has a new setting `preserveDOM` which will not clone DOM nodes if present. This can be useful in scenarios where you want to clone an object with references to the live DOM you want to maintain
20-
* **Utils** - Added `log()` function for flexible logging with formatting, namespacing, timestamps, and JSON output support
21-
* **Utils** - Renamed `errors.js` module to `debug.js` to better reflect its logging and debugging capabilities
12+
* **Attach** - Added new `attach` behavior that allows you to position elements relative to other elements using `css anchor` positioning.
2213

2314
## Breaking Changes
2415
* **Utils** - `deepExtend` now preserves non clonables by default. This is to prevent very common scenarios where extend is used with custom classes or dom elements where the original reference should be maintained. Note this still can be overwritten using `deepExtend(obj1, obj2, { preserveNonCloneable: false });`
@@ -44,6 +35,13 @@ Please note after `1.0` Semver will be followed using normal protocols.
4435
* **Enhancement** - [`closest()`](https://next.semantic-ui.com/api/query/dom-traversal#closest) now supports passing DOM elements directly as the selector parameter, checking containment using the element's `contains()` method.
4536
* **Bug** - Fixed CSS nesting parsing in [`naturalDisplay()`](https://next.semantic-ui.com/api/query/dimensions#naturaldisplay) to properly resolve nested selectors with `&` parent references (e.g., `& .grid-container`).
4637
* **Bug** - Fixed [`position()`](https://next.semantic-ui.com/api/query/dimensions#position) method to return `undefined` for empty selections instead of empty array when used as getter.
38+
* **Bug** - Fixed issue where using non clonables as settings like query collections, or custom classes wouldn't work as expected. This was related to the default behavior of deepExtend and clone (see breaking changes).
39+
* **Bug** - Fixed bug in `is` where it would return true for non-existent selectors
40+
41+
## Utils
42+
* **Feature** - Clone now has a new setting `preserveDOM` which will not clone DOM nodes if present. This can be useful in scenarios where you want to clone an object with references to the live DOM you want to maintain
43+
* **Feature** - Added `log()` function for flexible logging with formatting, namespacing, timestamps, and JSON output support
44+
* **Feature** - Renamed `errors.js` module to `debug.js` to better reflect its logging and debugging capabilities
4745

4846
# Version 0.16.1-2 - 08.21.2025
4947

ai/packages/query.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,21 +167,31 @@ The Query class provides a comprehensive set of methods organized into logical c
167167
- `pagePosition(options)` - Get document-relative position (viewport + scroll)
168168
- `dimensions()` - Get comprehensive dimension info (position, size, box model)
169169
- `bounds()` - Get DOMRect bounding box information
170+
<<<<<<< HEAD
170171
- `intersects(target, options)` - Check if elements intersect with target (with threshold, sides, details, all)
172+
=======
173+
>>>>>>> next
171174
- `offsetParent(options)` - Get offset parent for positioning
172175
- `naturalWidth()`, `naturalHeight()` - Get natural dimensions
173176
- `naturalDisplay(options)` - Get natural display value (ignoring display: none)
174177
- `clippingParent()` - Get element that clips visual bounds
175178
- `containingParent()` - Get simple containing parent (offsetParent)
176179
- `positioningParent(options)` - Get accurate positioning context parent
180+
<<<<<<< HEAD
177181
- `scrollParent(options)` - Get nearest scrollable container or all scroll parents in hierarchy
182+
=======
183+
>>>>>>> next
178184
179185
### Visibility and Display
180186
- `show(options)` - Show hidden elements using natural display value
181187
- `hide()` - Hide elements by setting display: none
182188
- `toggle(options)` - Toggle visibility state
183189
- `isVisible(options)` - Check if elements are visible (with opacity/visibility checks)
190+
<<<<<<< HEAD
184191
- `isInView(options)` - Check if elements are within viewport bounds (inherits all intersects options)
192+
=======
193+
- `isInViewport(options)` - Check if elements are within viewport bounds (defaults to clipping parent)
194+
>>>>>>> next
185195
186196
### Component Integration (Semantic UI specific)
187197
- `settings(newSettings)` - Configure component settings
@@ -866,7 +876,11 @@ console.log('Scrollable area:', dims.scrollWidth, dims.scrollHeight);
866876
// Lazy loading with viewport detection (uses clipping parent by default)
867877
function setupLazyLoading() {
868878
$('.lazy-image').each((img) => {
879+
<<<<<<< HEAD
869880
if ($(img).isInView({ threshold: 0.1 })) {
881+
=======
882+
if ($(img).isInViewport({ threshold: 0.1 })) {
883+
>>>>>>> next
870884
img.src = img.dataset.src;
871885
img.classList.remove('lazy-image');
872886
}
@@ -877,21 +891,30 @@ function setupLazyLoading() {
877891
$('#content-area').on('scroll', () => {
878892
$('.animate-on-scroll').each((element) => {
879893
// Check visibility within the scrolling content area
894+
<<<<<<< HEAD
880895
if ($(element).isInView({ threshold: 0.5 })) {
896+
=======
897+
if ($(element).isInViewport({ threshold: 0.5 })) {
898+
>>>>>>> next
881899
element.classList.add('animated');
882900
}
883901
});
884902
});
885903

886904
// Check visibility within custom viewport (modal, sidebar, etc.)
905+
<<<<<<< HEAD
887906
if ($('.modal-content').isInView({ fully: true, viewport: $('#modal') })) {
907+
=======
908+
if ($('.modal-content').isInViewport({ fully: true, viewport: $('#modal') })) {
909+
>>>>>>> next
888910
console.log('Modal content is fully visible within modal viewport');
889911
}
890912

891913
// Progressive reveal based on browser viewport
892914
$('.reveal-items').each((item) => {
893915
const $item = $(item);
894916
// Explicitly use browser viewport instead of clipping parent
917+
<<<<<<< HEAD
895918
if ($item.isInView({ threshold: 0.25, viewport: document.documentElement })) {
896919
$item.addClass('fade-in');
897920
}
@@ -919,6 +942,12 @@ if ($('.draggable-items').intersects('.drop-zone', { all: true, threshold: 0.8 }
919942
console.log('All items are mostly within drop zone');
920943
$('.drop-zone').addClass('ready-for-drop');
921944
}
945+
=======
946+
if ($item.isInViewport({ threshold: 0.25, viewport: document.documentElement })) {
947+
$item.addClass('fade-in');
948+
}
949+
});
950+
>>>>>>> next
922951
```
923952
924953
### Dynamic Positioning
@@ -952,6 +981,7 @@ function positionTooltip($tooltip, $trigger) {
952981
$tooltip.css({ top: `${top}px`, left: `${left}px` });
953982
}
954983

984+
<<<<<<< HEAD
955985
// Position tooltip within scrollable container
956986
function positionTooltipInScroller($tooltip, $trigger) {
957987
const $scrollContainer = $trigger.scrollParent();
@@ -986,6 +1016,8 @@ function setupScrollAwareTooltip($trigger, $tooltip) {
9861016
});
9871017
}
9881018

1019+
=======
1020+
>>>>>>> next
9891021
// Relative positioning for connected elements
9901022
$('#draggable').on('drag', (event) => {
9911023
// Position connected indicator relative to draggable
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
title: 'Query .isInViewport()'
3+
shortTitle: '.isInViewport()'
4+
id: 'query-is-in-viewport'
5+
exampleType: 'component'
6+
category: 'Query'
7+
subcategory: 'Visibility'
8+
tags: ['query', 'viewport', 'visibility', 'intersection', 'scroll']
9+
description: 'Checks if elements are within the viewport bounds with threshold support'
10+
tip: 'Useful for lazy loading, animations, and scroll-triggered effects based on viewport visibility'
11+
selectedFile: 'page.js'
12+
---
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
.scroll-container {
2+
height: 300px;
3+
overflow-y: auto;
4+
padding: var(--padding);
5+
background: var(--standard-1);
6+
border: var(--border);
7+
border-radius: var(--border-radius);
8+
margin: var(--margin) 0;
9+
}
10+
11+
.test-element {
12+
width: 200px;
13+
height: 100px;
14+
background: var(--blue-10);
15+
border: 2px solid var(--blue-30);
16+
color: var(--blue-70);
17+
display: flex;
18+
align-items: center;
19+
justify-content: center;
20+
margin: 0 auto 20px;
21+
border-radius: var(--border-radius);
22+
font-weight: bold;
23+
font-size: 16px;
24+
transition: all 0.3s ease;
25+
}
26+
27+
.test-element.in-viewport {
28+
background: var(--green-10);
29+
border-color: var(--green-30);
30+
color: var(--green-70);
31+
transform: scale(1.05);
32+
box-shadow: 0 8px 25px var(--green-20);
33+
}
34+
35+
.test-element.partially-visible {
36+
background: var(--orange-10);
37+
border-color: var(--orange-30);
38+
color: var(--orange-70);
39+
}
40+
41+
.spacer {
42+
height: 200px;
43+
display: flex;
44+
align-items: center;
45+
justify-content: center;
46+
color: var(--standard-50);
47+
font-style: italic;
48+
}
49+
50+
.spacer.bottom {
51+
height: 100px;
52+
}
53+
54+
ui-button {
55+
margin: 5px;
56+
}
57+
58+
.output {
59+
background: var(--standard-5);
60+
border: var(--border);
61+
border-radius: var(--border-radius);
62+
padding: var(--padding);
63+
margin: var(--margin) 0;
64+
}
65+
66+
.output h3 {
67+
margin-top: 0;
68+
color: var(--standard-70);
69+
}
70+
71+
#viewport-info {
72+
background: var(--standard-0);
73+
padding: var(--padding);
74+
border-radius: var(--border-radius);
75+
border: var(--border);
76+
white-space: pre-wrap;
77+
font-family: monospace;
78+
font-size: 13px;
79+
line-height: 1.4;
80+
max-height: 200px;
81+
overflow-y: auto;
82+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<p>Check viewport visibility with threshold and fully options</p>
2+
3+
<div class="scroll-container" id="scroll-area">
4+
<div class="spacer">Scroll down to see elements...</div>
5+
6+
<div class="test-element" data-name="Element 1">Element 1</div>
7+
<div class="spacer">Scroll more...</div>
8+
9+
<div class="test-element" data-name="Element 2">Element 2</div>
10+
<div class="spacer">Keep scrolling...</div>
11+
12+
<div class="test-element" data-name="Element 3">Element 3</div>
13+
<div class="spacer bottom">End of content</div>
14+
</div>
15+
16+
<ui-button id="check-viewport">Check Viewport</ui-button>
17+
<ui-button id="check-threshold">Check 50% Threshold</ui-button>
18+
<ui-button id="check-fully">Check Fully Visible</ui-button>
19+
<ui-button id="scroll-to-middle">Scroll to Middle</ui-button>
20+
21+
<div class="output">
22+
<h3>Viewport Status</h3>
23+
<pre id="viewport-info"></pre>
24+
</div>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { $ } from '@semantic-ui/query';
2+
3+
function checkViewportStatus(options = {}) {
4+
let info = 'CLIPPING PARENT VISIBILITY CHECK';
5+
6+
if (options.threshold !== undefined) {
7+
info += ` (${Math.round(options.threshold * 100)}% threshold)`;
8+
}
9+
if (options.fully) {
10+
info += ' (fully visible only)';
11+
}
12+
13+
info += ':\n\n';
14+
15+
$('.test-element').each((element) => {
16+
const $element = $(element);
17+
const name = $element.attr('data-name');
18+
const isVisible = $element.isInViewport(options);
19+
20+
info += `${name}: ${isVisible ? '✓ VISIBLE IN CONTAINER' : '✗ NOT VISIBLE IN CONTAINER'}\n`;
21+
22+
// Visual feedback
23+
$element.removeClass('in-viewport partially-visible');
24+
if (isVisible) {
25+
$element.addClass('in-viewport');
26+
}
27+
else if ($element.isInViewport()) {
28+
$element.addClass('partially-visible');
29+
}
30+
});
31+
32+
// Check all elements together
33+
const allVisible = $('.test-element').isInViewport(options);
34+
info += `\nAll elements visible in container: ${allVisible ? '✓ YES' : '✗ NO'}`;
35+
36+
$('#viewport-info').text(info);
37+
}
38+
39+
// Event handlers using Query
40+
$('#check-viewport').on('click', () => {
41+
checkViewportStatus();
42+
});
43+
44+
$('#check-threshold').on('click', () => {
45+
checkViewportStatus({ threshold: 0.5 });
46+
});
47+
48+
$('#check-fully').on('click', () => {
49+
checkViewportStatus({ fully: true });
50+
});
51+
52+
$('#scroll-to-middle').on('click', () => {
53+
const container = $('#scroll-area').el();
54+
const scrollHeight = container.scrollHeight;
55+
const clientHeight = container.clientHeight;
56+
container.scrollTop = (scrollHeight - clientHeight) / 2;
57+
58+
// Check after scroll
59+
setTimeout(() => checkViewportStatus(), 100);
60+
});
61+
62+
// Check on scroll
63+
$('#scroll-area').on('scroll', () => {
64+
checkViewportStatus();
65+
});
66+
67+
// Initial check
68+
checkViewportStatus();

0 commit comments

Comments
 (0)