slim-select 3.2.0 → 3.4.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 +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/react/index.d.ts +7 -0
- package/dist/react/index.js +291 -246
- package/dist/react/index.umd.js +2 -2
- package/dist/slimselect.cjs.js +1 -1
- package/dist/slimselect.cjs.js.map +1 -1
- package/dist/slimselect.css +1 -1
- package/dist/slimselect.css.map +1 -1
- package/dist/slimselect.es.js +308 -263
- package/dist/slimselect.es.js.map +1 -1
- package/dist/slimselect.iife.js +1 -1
- package/dist/slimselect.iife.js.map +1 -1
- package/dist/slimselect.js +1 -1
- package/dist/slimselect.js.map +1 -1
- package/dist/vue/index.d.ts +7 -0
- package/dist/vue/index.js +214 -169
- package/dist/vue/index.umd.js +1 -1
- package/package.json +24 -23
- package/sitemap.js +21 -2
- package/src/slim-select/classes.test.ts +3 -3
- package/src/slim-select/classes.ts +40 -34
- package/src/slim-select/index.test.ts +26 -5
- package/src/slim-select/index.ts +12 -0
- package/src/slim-select/render.test.ts +216 -0
- package/src/slim-select/render.ts +204 -115
- package/src/slim-select/select.ts +11 -7
- package/src/slim-select/settings.test.ts +2 -1
- package/src/slim-select/settings.ts +2 -0
- package/src/slim-select/slimselect.scss +5 -0
|
@@ -1658,4 +1658,220 @@ describe('render module', () => {
|
|
|
1658
1658
|
expect(render.content.main.classList.contains(render.classes.dirBelow)).toBe(true)
|
|
1659
1659
|
})
|
|
1660
1660
|
})
|
|
1661
|
+
|
|
1662
|
+
describe('setContentPosition (via moveContentBelow)', () => {
|
|
1663
|
+
// Helper: mock getBoundingClientRect on an element to return specific values
|
|
1664
|
+
function mockRect(el: HTMLElement, rect: Partial<DOMRect>) {
|
|
1665
|
+
el.getBoundingClientRect = vi.fn(
|
|
1666
|
+
() =>
|
|
1667
|
+
({
|
|
1668
|
+
top: 0,
|
|
1669
|
+
left: 0,
|
|
1670
|
+
right: 0,
|
|
1671
|
+
bottom: 0,
|
|
1672
|
+
width: 0,
|
|
1673
|
+
height: 0,
|
|
1674
|
+
x: 0,
|
|
1675
|
+
y: 0,
|
|
1676
|
+
toJSON: () => {},
|
|
1677
|
+
...rect
|
|
1678
|
+
}) as DOMRect
|
|
1679
|
+
)
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
test('absolute (default): content aligns below trigger using document coords', () => {
|
|
1683
|
+
// Simulate trigger at viewport (100, 50) with height 40 and width 200
|
|
1684
|
+
mockRect(render.main.main, { top: 100, left: 50, height: 40, width: 200 })
|
|
1685
|
+
|
|
1686
|
+
// No scroll
|
|
1687
|
+
Object.defineProperty(window, 'scrollY', { value: 0, writable: true })
|
|
1688
|
+
Object.defineProperty(window, 'scrollX', { value: 0, writable: true })
|
|
1689
|
+
|
|
1690
|
+
render.settings.contentPosition = 'absolute'
|
|
1691
|
+
render.moveContentBelow()
|
|
1692
|
+
|
|
1693
|
+
// top = viewportTop(100) + scrollY(0) + height(40) = 140
|
|
1694
|
+
// left = viewportLeft(50) + scrollX(0) = 50
|
|
1695
|
+
expect(render.content.main.style.top).toBe('140px')
|
|
1696
|
+
expect(render.content.main.style.left).toBe('50px')
|
|
1697
|
+
expect(render.content.main.style.width).toBe('200px')
|
|
1698
|
+
})
|
|
1699
|
+
|
|
1700
|
+
test('absolute: content accounts for page scroll', () => {
|
|
1701
|
+
// Trigger at viewport (100, 50) but page is scrolled down 300px and right 20px
|
|
1702
|
+
mockRect(render.main.main, { top: 100, left: 50, height: 40, width: 200 })
|
|
1703
|
+
|
|
1704
|
+
Object.defineProperty(window, 'scrollY', { value: 300, writable: true })
|
|
1705
|
+
Object.defineProperty(window, 'scrollX', { value: 20, writable: true })
|
|
1706
|
+
|
|
1707
|
+
render.settings.contentPosition = 'absolute'
|
|
1708
|
+
render.moveContentBelow()
|
|
1709
|
+
|
|
1710
|
+
// top = viewportTop(100) + scrollY(300) + height(40) = 440
|
|
1711
|
+
// left = viewportLeft(50) + scrollX(20) = 70
|
|
1712
|
+
expect(render.content.main.style.top).toBe('440px')
|
|
1713
|
+
expect(render.content.main.style.left).toBe('70px')
|
|
1714
|
+
expect(render.content.main.style.width).toBe('200px')
|
|
1715
|
+
})
|
|
1716
|
+
|
|
1717
|
+
test('absolute: content aligns correctly when trigger is near top of page', () => {
|
|
1718
|
+
// Trigger is at very top, no scroll
|
|
1719
|
+
mockRect(render.main.main, { top: 0, left: 10, height: 30, width: 150 })
|
|
1720
|
+
|
|
1721
|
+
Object.defineProperty(window, 'scrollY', { value: 0, writable: true })
|
|
1722
|
+
Object.defineProperty(window, 'scrollX', { value: 0, writable: true })
|
|
1723
|
+
|
|
1724
|
+
render.settings.contentPosition = 'absolute'
|
|
1725
|
+
render.moveContentBelow()
|
|
1726
|
+
|
|
1727
|
+
// top = 0 + 0 + 30 = 30
|
|
1728
|
+
// left = 10 + 0 = 10
|
|
1729
|
+
expect(render.content.main.style.top).toBe('30px')
|
|
1730
|
+
expect(render.content.main.style.left).toBe('10px')
|
|
1731
|
+
expect(render.content.main.style.width).toBe('150px')
|
|
1732
|
+
})
|
|
1733
|
+
|
|
1734
|
+
test('fixed: content uses viewport coords without scroll offset', () => {
|
|
1735
|
+
// Same trigger position and scroll as the absolute+scroll test
|
|
1736
|
+
mockRect(render.main.main, { top: 100, left: 50, height: 40, width: 200 })
|
|
1737
|
+
|
|
1738
|
+
Object.defineProperty(window, 'scrollY', { value: 300, writable: true })
|
|
1739
|
+
Object.defineProperty(window, 'scrollX', { value: 20, writable: true })
|
|
1740
|
+
|
|
1741
|
+
render.settings.contentPosition = 'fixed'
|
|
1742
|
+
render.moveContentBelow()
|
|
1743
|
+
|
|
1744
|
+
// Fixed ignores scroll: top = viewportTop(100) + height(40) = 140
|
|
1745
|
+
// left = viewportLeft(50) = 50
|
|
1746
|
+
expect(render.content.main.style.top).toBe('140px')
|
|
1747
|
+
expect(render.content.main.style.left).toBe('50px')
|
|
1748
|
+
expect(render.content.main.style.width).toBe('200px')
|
|
1749
|
+
})
|
|
1750
|
+
|
|
1751
|
+
test('relative: content position styles are not set', () => {
|
|
1752
|
+
mockRect(render.main.main, { top: 100, left: 50, height: 40, width: 200 })
|
|
1753
|
+
|
|
1754
|
+
render.settings.contentPosition = 'relative'
|
|
1755
|
+
|
|
1756
|
+
// Reset styles to confirm they aren't changed
|
|
1757
|
+
render.content.main.style.top = ''
|
|
1758
|
+
render.content.main.style.left = ''
|
|
1759
|
+
render.content.main.style.width = ''
|
|
1760
|
+
|
|
1761
|
+
render.moveContentBelow()
|
|
1762
|
+
|
|
1763
|
+
// setContentPosition returns early for relative, so no inline positioning
|
|
1764
|
+
expect(render.content.main.style.top).toBe('')
|
|
1765
|
+
expect(render.content.main.style.left).toBe('')
|
|
1766
|
+
expect(render.content.main.style.width).toBe('')
|
|
1767
|
+
})
|
|
1768
|
+
|
|
1769
|
+
test('absolute vs fixed diverge only by scroll offset', () => {
|
|
1770
|
+
const triggerRect = { top: 200, left: 80, height: 36, width: 250 }
|
|
1771
|
+
|
|
1772
|
+
Object.defineProperty(window, 'scrollY', { value: 500, writable: true })
|
|
1773
|
+
Object.defineProperty(window, 'scrollX', { value: 0, writable: true })
|
|
1774
|
+
|
|
1775
|
+
// Absolute
|
|
1776
|
+
mockRect(render.main.main, triggerRect)
|
|
1777
|
+
render.settings.contentPosition = 'absolute'
|
|
1778
|
+
render.moveContentBelow()
|
|
1779
|
+
const absTop = render.content.main.style.top
|
|
1780
|
+
const absLeft = render.content.main.style.left
|
|
1781
|
+
|
|
1782
|
+
// Fixed
|
|
1783
|
+
mockRect(render.main.main, triggerRect)
|
|
1784
|
+
render.settings.contentPosition = 'fixed'
|
|
1785
|
+
render.moveContentBelow()
|
|
1786
|
+
const fixedTop = render.content.main.style.top
|
|
1787
|
+
const fixedLeft = render.content.main.style.left
|
|
1788
|
+
|
|
1789
|
+
// Absolute top should be exactly scrollY more than fixed top
|
|
1790
|
+
expect(parseFloat(absTop)).toBe(parseFloat(fixedTop) + 500)
|
|
1791
|
+
// Left should differ by scrollX (which is 0 here, so equal)
|
|
1792
|
+
expect(parseFloat(absLeft)).toBe(parseFloat(fixedLeft))
|
|
1793
|
+
})
|
|
1794
|
+
|
|
1795
|
+
describe('contentWidth setting', () => {
|
|
1796
|
+
beforeEach(() => {
|
|
1797
|
+
mockRect(render.main.main, { top: 100, left: 50, height: 40, width: 200 })
|
|
1798
|
+
Object.defineProperty(window, 'scrollY', { value: 0, writable: true })
|
|
1799
|
+
Object.defineProperty(window, 'scrollX', { value: 0, writable: true })
|
|
1800
|
+
render.settings.contentPosition = 'absolute'
|
|
1801
|
+
})
|
|
1802
|
+
|
|
1803
|
+
test('default (empty): width matches trigger', () => {
|
|
1804
|
+
render.settings.contentWidth = ''
|
|
1805
|
+
render.moveContentBelow()
|
|
1806
|
+
|
|
1807
|
+
expect(render.content.main.style.width).toBe('200px')
|
|
1808
|
+
expect(render.content.main.style.minWidth).toBe('')
|
|
1809
|
+
expect(render.content.main.style.maxWidth).toBe('')
|
|
1810
|
+
})
|
|
1811
|
+
|
|
1812
|
+
test('exact value: sets width to given value', () => {
|
|
1813
|
+
render.settings.contentWidth = '500px'
|
|
1814
|
+
render.moveContentBelow()
|
|
1815
|
+
|
|
1816
|
+
expect(render.content.main.style.width).toBe('500px')
|
|
1817
|
+
expect(render.content.main.style.minWidth).toBe('')
|
|
1818
|
+
expect(render.content.main.style.maxWidth).toBe('')
|
|
1819
|
+
})
|
|
1820
|
+
|
|
1821
|
+
test('> prefix: sets min-width, no fixed width', () => {
|
|
1822
|
+
render.settings.contentWidth = '>300px'
|
|
1823
|
+
render.moveContentBelow()
|
|
1824
|
+
|
|
1825
|
+
expect(render.content.main.style.minWidth).toBe('300px')
|
|
1826
|
+
expect(render.content.main.style.width).toBe('')
|
|
1827
|
+
expect(render.content.main.style.maxWidth).toBe('')
|
|
1828
|
+
})
|
|
1829
|
+
|
|
1830
|
+
test('< prefix: sets max-width, no fixed width', () => {
|
|
1831
|
+
render.settings.contentWidth = '<600px'
|
|
1832
|
+
render.moveContentBelow()
|
|
1833
|
+
|
|
1834
|
+
expect(render.content.main.style.maxWidth).toBe('600px')
|
|
1835
|
+
expect(render.content.main.style.width).toBe('')
|
|
1836
|
+
expect(render.content.main.style.minWidth).toBe('')
|
|
1837
|
+
})
|
|
1838
|
+
|
|
1839
|
+
test('exact value with percentage', () => {
|
|
1840
|
+
render.settings.contentWidth = '100%'
|
|
1841
|
+
render.moveContentBelow()
|
|
1842
|
+
|
|
1843
|
+
expect(render.content.main.style.width).toBe('100%')
|
|
1844
|
+
expect(render.content.main.style.minWidth).toBe('')
|
|
1845
|
+
expect(render.content.main.style.maxWidth).toBe('')
|
|
1846
|
+
})
|
|
1847
|
+
|
|
1848
|
+
test('clears previous width styles when switching modes', () => {
|
|
1849
|
+
// First set min-width
|
|
1850
|
+
render.settings.contentWidth = '>300px'
|
|
1851
|
+
render.moveContentBelow()
|
|
1852
|
+
expect(render.content.main.style.minWidth).toBe('300px')
|
|
1853
|
+
|
|
1854
|
+
// Now switch to exact width — min-width should be cleared
|
|
1855
|
+
render.settings.contentWidth = '500px'
|
|
1856
|
+
render.moveContentBelow()
|
|
1857
|
+
expect(render.content.main.style.width).toBe('500px')
|
|
1858
|
+
expect(render.content.main.style.minWidth).toBe('')
|
|
1859
|
+
expect(render.content.main.style.maxWidth).toBe('')
|
|
1860
|
+
})
|
|
1861
|
+
|
|
1862
|
+
test('clears previous width styles when switching to default', () => {
|
|
1863
|
+
// First set max-width
|
|
1864
|
+
render.settings.contentWidth = '<600px'
|
|
1865
|
+
render.moveContentBelow()
|
|
1866
|
+
expect(render.content.main.style.maxWidth).toBe('600px')
|
|
1867
|
+
|
|
1868
|
+
// Now switch to default — max-width should be cleared, width matches trigger
|
|
1869
|
+
render.settings.contentWidth = ''
|
|
1870
|
+
render.moveContentBelow()
|
|
1871
|
+
expect(render.content.main.style.width).toBe('200px')
|
|
1872
|
+
expect(render.content.main.style.minWidth).toBe('')
|
|
1873
|
+
expect(render.content.main.style.maxWidth).toBe('')
|
|
1874
|
+
})
|
|
1875
|
+
})
|
|
1876
|
+
})
|
|
1661
1877
|
})
|