@brytdesigns/web-component-gnav-header 1.0.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.
@@ -0,0 +1,241 @@
1
+ import { customShadowlessElement, correctElementType } from '@brytdesigns/web-component-core/utils';
2
+ import { awaitAllAnimations } from '@brytdesigns/web-component-core/animation';
3
+ import { debounce } from '@solid-primitives/scheduled';
4
+ import { createSignal, onCleanup, createEffect, on } from 'solid-js';
5
+ import { animate } from 'motion';
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+
13
+ // src/components/gnav-header.ts
14
+ var gnav_header_exports = {};
15
+ __export(gnav_header_exports, {
16
+ Component: () => Component,
17
+ Name: () => Name
18
+ });
19
+
20
+ // src/utils.ts
21
+ var groupBy = (list, getKey) => list.reduce(
22
+ (previous, currentItem, index) => {
23
+ const group = getKey(currentItem, index);
24
+ if (!previous[group]) previous[group] = [];
25
+ previous[group].push(currentItem);
26
+ return previous;
27
+ },
28
+ {}
29
+ );
30
+ var CSSVars = {
31
+ headerHeight: "--header-height",
32
+ collapsedHeaderHeight: "--collapsed-header-height",
33
+ stickyHeaderHeight: "--sticky-header-height",
34
+ stickyHeaderTop: "--sticky-header-top"
35
+ };
36
+ function updateCssVar(host, varName, amount) {
37
+ host.style.setProperty(CSSVars[varName], `${amount}px`);
38
+ }
39
+ function getCssVarValue(host, varName) {
40
+ const raw = getComputedStyle(host).getPropertyValue(CSSVars[varName]);
41
+ return parseFloat(raw) || 0;
42
+ }
43
+
44
+ // src/components/gnav-header.ts
45
+ var Name = `gnav-header`;
46
+ var SECTION_TAG = "gnav-header-section";
47
+ function awaitInFlightSectionAnimations(sections) {
48
+ return Promise.allSettled(
49
+ sections.flatMap(
50
+ (section) => section.getAnimations().map((animation) => animation.finished)
51
+ )
52
+ );
53
+ }
54
+ function nodesContainSection(nodes) {
55
+ return Array.from(nodes).some(
56
+ (node) => node instanceof Element && (node.tagName.toLowerCase() === SECTION_TAG || node.querySelector(SECTION_TAG) !== null)
57
+ );
58
+ }
59
+ var Component = (props, { element }) => {
60
+ const [sections, setSections] = createSignal([]);
61
+ let runId = 0;
62
+ function setupSection(section, position) {
63
+ section.setAttribute("position", String(position));
64
+ if (!section.style.position) section.style.position = "relative";
65
+ if (section.hasAttribute("hide-on-trigger")) section.style.zIndex = "99";
66
+ else section.style.zIndex = "100";
67
+ }
68
+ function refreshSections() {
69
+ const found = Array.from(
70
+ document.querySelectorAll(SECTION_TAG)
71
+ );
72
+ found.forEach((section, i) => setupSection(section, i + 1));
73
+ setSections(found);
74
+ }
75
+ refreshSections();
76
+ if (!sections().length) {
77
+ console.warn("No gnav-header-section found!");
78
+ }
79
+ updateCssVar(element, "headerHeight", element.offsetHeight);
80
+ updateCssVar(element, "collapsedHeaderHeight", getCollapsedHeaderHeight());
81
+ const observer = new MutationObserver((mutations) => {
82
+ const relevant = mutations.some(
83
+ (m) => nodesContainSection(m.addedNodes) || nodesContainSection(m.removedNodes)
84
+ );
85
+ if (relevant) refreshSections();
86
+ });
87
+ observer.observe(document.body, { childList: true, subtree: true });
88
+ onCleanup(() => observer.disconnect());
89
+ createEffect(
90
+ on(
91
+ () => props.scrollThreshold,
92
+ (scrollThreshold) => {
93
+ const controller = new AbortController();
94
+ let previousScroll = window.scrollY;
95
+ function handleScroll() {
96
+ const delta = window.scrollY - previousScroll;
97
+ if (Math.abs(delta) < scrollThreshold) return;
98
+ element.setAttribute("collapsed", String(delta > 0));
99
+ previousScroll = Math.max(0, window.scrollY);
100
+ }
101
+ const handleResize = debounce(function() {
102
+ updateCssVar(element, "headerHeight", element.offsetHeight);
103
+ updateCssVar(
104
+ element,
105
+ "collapsedHeaderHeight",
106
+ getCollapsedHeaderHeight()
107
+ );
108
+ if (props.collapsed) handleScrollDownAnimation();
109
+ else handleScrollUpAnimation();
110
+ }, 200);
111
+ window.addEventListener("scroll", handleScroll, {
112
+ capture: true,
113
+ signal: controller.signal
114
+ });
115
+ window.addEventListener("resize", handleResize, {
116
+ capture: true,
117
+ signal: controller.signal
118
+ });
119
+ onCleanup(() => {
120
+ controller.abort();
121
+ handleResize.clear();
122
+ });
123
+ }
124
+ )
125
+ );
126
+ createEffect(
127
+ on(
128
+ () => props.collapsed,
129
+ (collapsed) => {
130
+ if (collapsed) {
131
+ return handleScrollDownAnimation();
132
+ }
133
+ return handleScrollUpAnimation();
134
+ }
135
+ )
136
+ );
137
+ function shouldHideSectionOnTrigger(section) {
138
+ return section.hasAttribute("hide-on-trigger");
139
+ }
140
+ function getCollapsedHeaderHeight() {
141
+ return sections().reduce((total, section) => {
142
+ if (shouldHideSectionOnTrigger(section)) return total;
143
+ return total + section.getBoundingClientRect().height;
144
+ }, 0);
145
+ }
146
+ function getGroupedSections() {
147
+ return groupBy(
148
+ sections(),
149
+ (section) => shouldHideSectionOnTrigger(section) ? "hidden" : "visible"
150
+ );
151
+ }
152
+ async function handleScrollDownAnimation() {
153
+ const id = ++runId;
154
+ const currentSections = sections();
155
+ if (!currentSections.length) return;
156
+ await awaitInFlightSectionAnimations(currentSections);
157
+ if (id !== runId) return;
158
+ const animations = [];
159
+ const groupedSections = getGroupedSections();
160
+ if (!groupedSections.hidden) groupedSections.hidden = [];
161
+ if (!groupedSections.visible) groupedSections.visible = [];
162
+ let offset = groupedSections.hidden.reduce((total, el) => {
163
+ return total + el.getBoundingClientRect().height;
164
+ }, 0);
165
+ groupedSections.hidden.forEach((section) => {
166
+ const bounding = section.getBoundingClientRect();
167
+ const animation = animate(section, {
168
+ y: `${(section.offsetTop + offset) * -1}px`
169
+ });
170
+ offset -= bounding.height;
171
+ animations.push(animation);
172
+ });
173
+ offset = 0;
174
+ groupedSections.visible.forEach((section) => {
175
+ const bounding = section.getBoundingClientRect();
176
+ const animation = animate(section, {
177
+ y: `${offset - section.offsetTop}px`
178
+ });
179
+ offset += bounding.height;
180
+ animations.push(animation);
181
+ });
182
+ updateCssVar(element, "stickyHeaderHeight", offset);
183
+ updateCssVar(element, "collapsedHeaderHeight", offset);
184
+ animations.push(animateStickyHeaderTop());
185
+ return awaitAllAnimations(animations);
186
+ }
187
+ async function handleScrollUpAnimation() {
188
+ const id = ++runId;
189
+ const currentSections = sections();
190
+ if (!currentSections.length) return;
191
+ await awaitInFlightSectionAnimations(currentSections);
192
+ if (id !== runId) return;
193
+ updateCssVar(
194
+ element,
195
+ "stickyHeaderHeight",
196
+ element.getBoundingClientRect().height
197
+ );
198
+ return awaitAllAnimations([
199
+ animate(currentSections, {
200
+ y: "0px"
201
+ }),
202
+ animateStickyHeaderTop(false)
203
+ ]);
204
+ }
205
+ function animateStickyHeaderTop(isScrollingDown = true) {
206
+ let from = getCssVarValue(element, "stickyHeaderTop");
207
+ if (!from)
208
+ from = isScrollingDown ? element.offsetHeight : getCollapsedHeaderHeight();
209
+ const to = isScrollingDown ? getCollapsedHeaderHeight() : element.getBoundingClientRect().height;
210
+ return animate(from, to, {
211
+ onUpdate: (latest) => updateCssVar(element, "stickyHeaderTop", latest)
212
+ });
213
+ }
214
+ };
215
+
216
+ // src/components/gnav-header-section.ts
217
+ var gnav_header_section_exports = {};
218
+ __export(gnav_header_section_exports, {
219
+ Component: () => Component2,
220
+ Name: () => Name2
221
+ });
222
+ var Name2 = "gnav-header-section";
223
+ var Component2 = () => {
224
+ };
225
+
226
+ // src/index.ts
227
+ customShadowlessElement(
228
+ gnav_header_exports.Name,
229
+ {
230
+ scrollThreshold: 20,
231
+ collapsed: false
232
+ },
233
+ correctElementType(gnav_header_exports.Component)
234
+ );
235
+ customShadowlessElement(gnav_header_section_exports.Name, {
236
+ hideOnTrigger: false,
237
+ position: 0,
238
+ shouldTrigger: false
239
+ }, correctElementType(gnav_header_section_exports.Component));
240
+ //# sourceMappingURL=index.js.map
241
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/gnav-header.ts","../../src/utils.ts","../../src/components/gnav-header-section.ts","../../src/index.ts"],"names":["Component","Name"],"mappings":"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","file":"index.js","sourcesContent":["import { type CorrectComponentType } from \"@brytdesigns/web-component-core/utils\";\nimport { awaitAllAnimations } from \"@brytdesigns/web-component-core/animation\";\nimport { debounce } from \"@solid-primitives/scheduled\";\nimport { onCleanup, createEffect, createSignal, on } from \"solid-js\";\nimport { animate } from \"motion\";\n\nimport { groupBy, updateCssVar, getCssVarValue } from \"../utils.js\";\n\nexport type Props = {\n scrollThreshold: number;\n collapsed: boolean;\n};\n\nexport const Name = `gnav-header`;\n\nconst SECTION_TAG = \"gnav-header-section\";\n\nfunction awaitInFlightSectionAnimations(sections: HTMLElement[]) {\n return Promise.allSettled(\n sections.flatMap((section) =>\n section.getAnimations().map((animation) => animation.finished),\n ),\n );\n}\n\nfunction nodesContainSection(nodes: NodeList): boolean {\n return Array.from(nodes).some(\n (node) =>\n node instanceof Element &&\n (node.tagName.toLowerCase() === SECTION_TAG ||\n node.querySelector(SECTION_TAG) !== null),\n );\n}\n\nexport const Component: CorrectComponentType<Props> = (props, { element }) => {\n const [sections, setSections] = createSignal<HTMLElement[]>([]);\n let runId = 0;\n\n function setupSection(section: HTMLElement, position: number) {\n section.setAttribute(\"position\", String(position));\n if (!section.style.position) section.style.position = \"relative\";\n if (section.hasAttribute(\"hide-on-trigger\")) section.style.zIndex = \"99\";\n else section.style.zIndex = \"100\";\n }\n\n function refreshSections() {\n const found = Array.from(\n document.querySelectorAll<HTMLElement>(SECTION_TAG),\n );\n found.forEach((section, i) => setupSection(section, i + 1));\n setSections(found);\n }\n\n refreshSections();\n\n if (!sections().length) {\n console.warn(\"No gnav-header-section found!\");\n }\n\n updateCssVar(element, \"headerHeight\", element.offsetHeight);\n updateCssVar(element, \"collapsedHeaderHeight\", getCollapsedHeaderHeight());\n\n const observer = new MutationObserver((mutations) => {\n const relevant = mutations.some(\n (m) =>\n nodesContainSection(m.addedNodes) ||\n nodesContainSection(m.removedNodes),\n );\n if (relevant) refreshSections();\n });\n observer.observe(document.body, { childList: true, subtree: true });\n onCleanup(() => observer.disconnect());\n\n createEffect(\n on(\n () => props.scrollThreshold,\n (scrollThreshold) => {\n const controller = new AbortController();\n let previousScroll = window.scrollY;\n\n function handleScroll() {\n const delta = window.scrollY - previousScroll;\n if (Math.abs(delta) < scrollThreshold) return;\n element.setAttribute(\"collapsed\", String(delta > 0));\n previousScroll = Math.max(0, window.scrollY);\n }\n\n const handleResize = debounce(function () {\n updateCssVar(element, \"headerHeight\", element.offsetHeight);\n updateCssVar(\n element,\n \"collapsedHeaderHeight\",\n getCollapsedHeaderHeight(),\n );\n if (props.collapsed) handleScrollDownAnimation();\n else handleScrollUpAnimation();\n }, 200);\n\n window.addEventListener(\"scroll\", handleScroll, {\n capture: true,\n signal: controller.signal,\n });\n window.addEventListener(\"resize\", handleResize, {\n capture: true,\n signal: controller.signal,\n });\n\n onCleanup(() => {\n controller.abort();\n handleResize.clear();\n });\n },\n ),\n );\n\n createEffect(\n on(\n () => props.collapsed,\n (collapsed) => {\n if (collapsed) {\n return handleScrollDownAnimation();\n }\n return handleScrollUpAnimation();\n },\n ),\n );\n\n function shouldHideSectionOnTrigger(section: HTMLElement) {\n return section.hasAttribute(\"hide-on-trigger\");\n }\n\n function getCollapsedHeaderHeight() {\n return sections().reduce((total, section) => {\n if (shouldHideSectionOnTrigger(section)) return total;\n return total + section.getBoundingClientRect().height;\n }, 0);\n }\n\n function getGroupedSections() {\n return groupBy(sections(), (section) =>\n shouldHideSectionOnTrigger(section) ? \"hidden\" : \"visible\",\n );\n }\n\n async function handleScrollDownAnimation() {\n const id = ++runId;\n const currentSections = sections();\n if (!currentSections.length) return;\n\n await awaitInFlightSectionAnimations(currentSections);\n if (id !== runId) return;\n\n const animations = [];\n const groupedSections = getGroupedSections();\n\n if (!groupedSections.hidden) groupedSections.hidden = [];\n if (!groupedSections.visible) groupedSections.visible = [];\n\n let offset = groupedSections.hidden.reduce((total, el) => {\n return total + el.getBoundingClientRect().height;\n }, 0);\n\n groupedSections.hidden.forEach((section) => {\n const bounding = section.getBoundingClientRect();\n const animation = animate(section, {\n y: `${(section.offsetTop + offset) * -1}px`,\n });\n offset -= bounding.height;\n animations.push(animation);\n });\n\n offset = 0;\n\n groupedSections.visible.forEach((section) => {\n const bounding = section.getBoundingClientRect();\n const animation = animate(section, {\n y: `${offset - section.offsetTop}px`,\n });\n offset += bounding.height;\n animations.push(animation);\n });\n\n updateCssVar(element, \"stickyHeaderHeight\", offset);\n updateCssVar(element, \"collapsedHeaderHeight\", offset);\n\n animations.push(animateStickyHeaderTop());\n\n return awaitAllAnimations(animations);\n }\n\n async function handleScrollUpAnimation() {\n const id = ++runId;\n const currentSections = sections();\n if (!currentSections.length) return;\n\n await awaitInFlightSectionAnimations(currentSections);\n if (id !== runId) return;\n\n updateCssVar(\n element,\n \"stickyHeaderHeight\",\n element.getBoundingClientRect().height,\n );\n return awaitAllAnimations([\n animate(currentSections, {\n y: \"0px\",\n }),\n animateStickyHeaderTop(false),\n ]);\n }\n\n function animateStickyHeaderTop(isScrollingDown = true) {\n let from = getCssVarValue(element, \"stickyHeaderTop\");\n\n if (!from)\n from = isScrollingDown ? element.offsetHeight : getCollapsedHeaderHeight();\n\n const to = isScrollingDown\n ? getCollapsedHeaderHeight()\n : element.getBoundingClientRect().height;\n\n return animate(from, to, {\n onUpdate: (latest) => updateCssVar(element, \"stickyHeaderTop\", latest),\n });\n }\n};\n","export const groupBy = <T, K extends PropertyKey>(\n list: T[],\n getKey: (item: T, index: number) => K\n) =>\n list.reduce(\n (previous, currentItem, index) => {\n const group = getKey(currentItem, index);\n if (!previous[group]) previous[group] = [];\n previous[group].push(currentItem);\n return previous;\n },\n {} as Record<K, T[]>\n );\n\nexport const CSSVars = {\n headerHeight: \"--header-height\",\n collapsedHeaderHeight: \"--collapsed-header-height\",\n stickyHeaderHeight: \"--sticky-header-height\",\n stickyHeaderTop: \"--sticky-header-top\",\n} as const;\n\nexport function updateCssVar(\n host: HTMLElement,\n varName: keyof typeof CSSVars,\n amount: number\n) {\n host.style.setProperty(CSSVars[varName], `${amount}px`);\n}\n\nexport function getCssVarValue(\n host: HTMLElement,\n varName: keyof typeof CSSVars\n): number {\n const raw = getComputedStyle(host).getPropertyValue(CSSVars[varName]);\n return parseFloat(raw) || 0;\n}\n","import type { CorrectComponentType } from \"@brytdesigns/web-component-core/utils\";\n\nexport type Props = {\n shouldTrigger: boolean;\n position: number;\n hideOnTrigger: boolean;\n};\n\nexport const Name = \"gnav-header-section\";\n\nexport const Component: CorrectComponentType<Props> = () => {};\n","import {\n\tcorrectElementType,\n\tcustomShadowlessElement,\n} from \"@brytdesigns/web-component-core/utils\";\n\nimport { GnavHeader, GnavHeaderSection } from \"./components/index.js\";\n\nexport type GnavHeaderProps = GnavHeader.Props;\nexport type GnavHeaderSectionProps = GnavHeaderSection.Props;\n\ncustomShadowlessElement(\n\tGnavHeader.Name,\n\t{\n\t\tscrollThreshold: 20,\n\t\tcollapsed: false\n\t},\n\tcorrectElementType(GnavHeader.Component),\n);\n\ncustomShadowlessElement(GnavHeaderSection.Name, {\n\thideOnTrigger: false,\n\tposition: 0,\n\tshouldTrigger: false\n}, correctElementType(GnavHeaderSection.Component))"]}
@@ -0,0 +1,7 @@
1
+ const Name = "gnav-header-section";
2
+ const Component = () => {
3
+ };
4
+
5
+ export { Component, Name };
6
+ //# sourceMappingURL=gnav-header-section.js.map
7
+ //# sourceMappingURL=gnav-header-section.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/gnav-header-section.ts"],"names":[],"mappings":"AAQO,MAAM,IAAO,GAAA;AAEb,MAAM,YAAyC,MAAM;AAAC","file":"gnav-header-section.js","sourcesContent":["import type { CorrectComponentType } from \"@brytdesigns/web-component-core/utils\";\n\nexport type Props = {\n shouldTrigger: boolean;\n position: number;\n hideOnTrigger: boolean;\n};\n\nexport const Name = \"gnav-header-section\";\n\nexport const Component: CorrectComponentType<Props> = () => {};\n"]}
@@ -0,0 +1,181 @@
1
+ import '@brytdesigns/web-component-core/utils';
2
+ import { awaitAllAnimations } from '@brytdesigns/web-component-core/animation';
3
+ import { debounce } from '@solid-primitives/scheduled';
4
+ import { createSignal, onCleanup, createEffect, on } from 'solid-js';
5
+ import { animate } from 'motion';
6
+ import { updateCssVar, getCssVarValue, groupBy } from '../utils.js';
7
+
8
+ const Name = `gnav-header`;
9
+ const SECTION_TAG = "gnav-header-section";
10
+ function awaitInFlightSectionAnimations(sections) {
11
+ return Promise.allSettled(
12
+ sections.flatMap(
13
+ (section) => section.getAnimations().map((animation) => animation.finished)
14
+ )
15
+ );
16
+ }
17
+ function nodesContainSection(nodes) {
18
+ return Array.from(nodes).some(
19
+ (node) => node instanceof Element && (node.tagName.toLowerCase() === SECTION_TAG || node.querySelector(SECTION_TAG) !== null)
20
+ );
21
+ }
22
+ const Component = (props, { element }) => {
23
+ const [sections, setSections] = createSignal([]);
24
+ let runId = 0;
25
+ function setupSection(section, position) {
26
+ section.setAttribute("position", String(position));
27
+ if (!section.style.position) section.style.position = "relative";
28
+ if (section.hasAttribute("hide-on-trigger")) section.style.zIndex = "99";
29
+ else section.style.zIndex = "100";
30
+ }
31
+ function refreshSections() {
32
+ const found = Array.from(
33
+ document.querySelectorAll(SECTION_TAG)
34
+ );
35
+ found.forEach((section, i) => setupSection(section, i + 1));
36
+ setSections(found);
37
+ }
38
+ refreshSections();
39
+ if (!sections().length) {
40
+ console.warn("No gnav-header-section found!");
41
+ }
42
+ updateCssVar(element, "headerHeight", element.offsetHeight);
43
+ updateCssVar(element, "collapsedHeaderHeight", getCollapsedHeaderHeight());
44
+ const observer = new MutationObserver((mutations) => {
45
+ const relevant = mutations.some(
46
+ (m) => nodesContainSection(m.addedNodes) || nodesContainSection(m.removedNodes)
47
+ );
48
+ if (relevant) refreshSections();
49
+ });
50
+ observer.observe(document.body, { childList: true, subtree: true });
51
+ onCleanup(() => observer.disconnect());
52
+ createEffect(
53
+ on(
54
+ () => props.scrollThreshold,
55
+ (scrollThreshold) => {
56
+ const controller = new AbortController();
57
+ let previousScroll = window.scrollY;
58
+ function handleScroll() {
59
+ const delta = window.scrollY - previousScroll;
60
+ if (Math.abs(delta) < scrollThreshold) return;
61
+ element.setAttribute("collapsed", String(delta > 0));
62
+ previousScroll = Math.max(0, window.scrollY);
63
+ }
64
+ const handleResize = debounce(function() {
65
+ updateCssVar(element, "headerHeight", element.offsetHeight);
66
+ updateCssVar(
67
+ element,
68
+ "collapsedHeaderHeight",
69
+ getCollapsedHeaderHeight()
70
+ );
71
+ if (props.collapsed) handleScrollDownAnimation();
72
+ else handleScrollUpAnimation();
73
+ }, 200);
74
+ window.addEventListener("scroll", handleScroll, {
75
+ capture: true,
76
+ signal: controller.signal
77
+ });
78
+ window.addEventListener("resize", handleResize, {
79
+ capture: true,
80
+ signal: controller.signal
81
+ });
82
+ onCleanup(() => {
83
+ controller.abort();
84
+ handleResize.clear();
85
+ });
86
+ }
87
+ )
88
+ );
89
+ createEffect(
90
+ on(
91
+ () => props.collapsed,
92
+ (collapsed) => {
93
+ if (collapsed) {
94
+ return handleScrollDownAnimation();
95
+ }
96
+ return handleScrollUpAnimation();
97
+ }
98
+ )
99
+ );
100
+ function shouldHideSectionOnTrigger(section) {
101
+ return section.hasAttribute("hide-on-trigger");
102
+ }
103
+ function getCollapsedHeaderHeight() {
104
+ return sections().reduce((total, section) => {
105
+ if (shouldHideSectionOnTrigger(section)) return total;
106
+ return total + section.getBoundingClientRect().height;
107
+ }, 0);
108
+ }
109
+ function getGroupedSections() {
110
+ return groupBy(
111
+ sections(),
112
+ (section) => shouldHideSectionOnTrigger(section) ? "hidden" : "visible"
113
+ );
114
+ }
115
+ async function handleScrollDownAnimation() {
116
+ const id = ++runId;
117
+ const currentSections = sections();
118
+ if (!currentSections.length) return;
119
+ await awaitInFlightSectionAnimations(currentSections);
120
+ if (id !== runId) return;
121
+ const animations = [];
122
+ const groupedSections = getGroupedSections();
123
+ if (!groupedSections.hidden) groupedSections.hidden = [];
124
+ if (!groupedSections.visible) groupedSections.visible = [];
125
+ let offset = groupedSections.hidden.reduce((total, el) => {
126
+ return total + el.getBoundingClientRect().height;
127
+ }, 0);
128
+ groupedSections.hidden.forEach((section) => {
129
+ const bounding = section.getBoundingClientRect();
130
+ const animation = animate(section, {
131
+ y: `${(section.offsetTop + offset) * -1}px`
132
+ });
133
+ offset -= bounding.height;
134
+ animations.push(animation);
135
+ });
136
+ offset = 0;
137
+ groupedSections.visible.forEach((section) => {
138
+ const bounding = section.getBoundingClientRect();
139
+ const animation = animate(section, {
140
+ y: `${offset - section.offsetTop}px`
141
+ });
142
+ offset += bounding.height;
143
+ animations.push(animation);
144
+ });
145
+ updateCssVar(element, "stickyHeaderHeight", offset);
146
+ updateCssVar(element, "collapsedHeaderHeight", offset);
147
+ animations.push(animateStickyHeaderTop());
148
+ return awaitAllAnimations(animations);
149
+ }
150
+ async function handleScrollUpAnimation() {
151
+ const id = ++runId;
152
+ const currentSections = sections();
153
+ if (!currentSections.length) return;
154
+ await awaitInFlightSectionAnimations(currentSections);
155
+ if (id !== runId) return;
156
+ updateCssVar(
157
+ element,
158
+ "stickyHeaderHeight",
159
+ element.getBoundingClientRect().height
160
+ );
161
+ return awaitAllAnimations([
162
+ animate(currentSections, {
163
+ y: "0px"
164
+ }),
165
+ animateStickyHeaderTop(false)
166
+ ]);
167
+ }
168
+ function animateStickyHeaderTop(isScrollingDown = true) {
169
+ let from = getCssVarValue(element, "stickyHeaderTop");
170
+ if (!from)
171
+ from = isScrollingDown ? element.offsetHeight : getCollapsedHeaderHeight();
172
+ const to = isScrollingDown ? getCollapsedHeaderHeight() : element.getBoundingClientRect().height;
173
+ return animate(from, to, {
174
+ onUpdate: (latest) => updateCssVar(element, "stickyHeaderTop", latest)
175
+ });
176
+ }
177
+ };
178
+
179
+ export { Component, Name };
180
+ //# sourceMappingURL=gnav-header.js.map
181
+ //# sourceMappingURL=gnav-header.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/gnav-header.ts"],"names":[],"mappings":"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","file":"gnav-header.js","sourcesContent":["import { type CorrectComponentType } from \"@brytdesigns/web-component-core/utils\";\nimport { awaitAllAnimations } from \"@brytdesigns/web-component-core/animation\";\nimport { debounce } from \"@solid-primitives/scheduled\";\nimport { onCleanup, createEffect, createSignal, on } from \"solid-js\";\nimport { animate } from \"motion\";\n\nimport { groupBy, updateCssVar, getCssVarValue } from \"../utils.js\";\n\nexport type Props = {\n scrollThreshold: number;\n collapsed: boolean;\n};\n\nexport const Name = `gnav-header`;\n\nconst SECTION_TAG = \"gnav-header-section\";\n\nfunction awaitInFlightSectionAnimations(sections: HTMLElement[]) {\n return Promise.allSettled(\n sections.flatMap((section) =>\n section.getAnimations().map((animation) => animation.finished),\n ),\n );\n}\n\nfunction nodesContainSection(nodes: NodeList): boolean {\n return Array.from(nodes).some(\n (node) =>\n node instanceof Element &&\n (node.tagName.toLowerCase() === SECTION_TAG ||\n node.querySelector(SECTION_TAG) !== null),\n );\n}\n\nexport const Component: CorrectComponentType<Props> = (props, { element }) => {\n const [sections, setSections] = createSignal<HTMLElement[]>([]);\n let runId = 0;\n\n function setupSection(section: HTMLElement, position: number) {\n section.setAttribute(\"position\", String(position));\n if (!section.style.position) section.style.position = \"relative\";\n if (section.hasAttribute(\"hide-on-trigger\")) section.style.zIndex = \"99\";\n else section.style.zIndex = \"100\";\n }\n\n function refreshSections() {\n const found = Array.from(\n document.querySelectorAll<HTMLElement>(SECTION_TAG),\n );\n found.forEach((section, i) => setupSection(section, i + 1));\n setSections(found);\n }\n\n refreshSections();\n\n if (!sections().length) {\n console.warn(\"No gnav-header-section found!\");\n }\n\n updateCssVar(element, \"headerHeight\", element.offsetHeight);\n updateCssVar(element, \"collapsedHeaderHeight\", getCollapsedHeaderHeight());\n\n const observer = new MutationObserver((mutations) => {\n const relevant = mutations.some(\n (m) =>\n nodesContainSection(m.addedNodes) ||\n nodesContainSection(m.removedNodes),\n );\n if (relevant) refreshSections();\n });\n observer.observe(document.body, { childList: true, subtree: true });\n onCleanup(() => observer.disconnect());\n\n createEffect(\n on(\n () => props.scrollThreshold,\n (scrollThreshold) => {\n const controller = new AbortController();\n let previousScroll = window.scrollY;\n\n function handleScroll() {\n const delta = window.scrollY - previousScroll;\n if (Math.abs(delta) < scrollThreshold) return;\n element.setAttribute(\"collapsed\", String(delta > 0));\n previousScroll = Math.max(0, window.scrollY);\n }\n\n const handleResize = debounce(function () {\n updateCssVar(element, \"headerHeight\", element.offsetHeight);\n updateCssVar(\n element,\n \"collapsedHeaderHeight\",\n getCollapsedHeaderHeight(),\n );\n if (props.collapsed) handleScrollDownAnimation();\n else handleScrollUpAnimation();\n }, 200);\n\n window.addEventListener(\"scroll\", handleScroll, {\n capture: true,\n signal: controller.signal,\n });\n window.addEventListener(\"resize\", handleResize, {\n capture: true,\n signal: controller.signal,\n });\n\n onCleanup(() => {\n controller.abort();\n handleResize.clear();\n });\n },\n ),\n );\n\n createEffect(\n on(\n () => props.collapsed,\n (collapsed) => {\n if (collapsed) {\n return handleScrollDownAnimation();\n }\n return handleScrollUpAnimation();\n },\n ),\n );\n\n function shouldHideSectionOnTrigger(section: HTMLElement) {\n return section.hasAttribute(\"hide-on-trigger\");\n }\n\n function getCollapsedHeaderHeight() {\n return sections().reduce((total, section) => {\n if (shouldHideSectionOnTrigger(section)) return total;\n return total + section.getBoundingClientRect().height;\n }, 0);\n }\n\n function getGroupedSections() {\n return groupBy(sections(), (section) =>\n shouldHideSectionOnTrigger(section) ? \"hidden\" : \"visible\",\n );\n }\n\n async function handleScrollDownAnimation() {\n const id = ++runId;\n const currentSections = sections();\n if (!currentSections.length) return;\n\n await awaitInFlightSectionAnimations(currentSections);\n if (id !== runId) return;\n\n const animations = [];\n const groupedSections = getGroupedSections();\n\n if (!groupedSections.hidden) groupedSections.hidden = [];\n if (!groupedSections.visible) groupedSections.visible = [];\n\n let offset = groupedSections.hidden.reduce((total, el) => {\n return total + el.getBoundingClientRect().height;\n }, 0);\n\n groupedSections.hidden.forEach((section) => {\n const bounding = section.getBoundingClientRect();\n const animation = animate(section, {\n y: `${(section.offsetTop + offset) * -1}px`,\n });\n offset -= bounding.height;\n animations.push(animation);\n });\n\n offset = 0;\n\n groupedSections.visible.forEach((section) => {\n const bounding = section.getBoundingClientRect();\n const animation = animate(section, {\n y: `${offset - section.offsetTop}px`,\n });\n offset += bounding.height;\n animations.push(animation);\n });\n\n updateCssVar(element, \"stickyHeaderHeight\", offset);\n updateCssVar(element, \"collapsedHeaderHeight\", offset);\n\n animations.push(animateStickyHeaderTop());\n\n return awaitAllAnimations(animations);\n }\n\n async function handleScrollUpAnimation() {\n const id = ++runId;\n const currentSections = sections();\n if (!currentSections.length) return;\n\n await awaitInFlightSectionAnimations(currentSections);\n if (id !== runId) return;\n\n updateCssVar(\n element,\n \"stickyHeaderHeight\",\n element.getBoundingClientRect().height,\n );\n return awaitAllAnimations([\n animate(currentSections, {\n y: \"0px\",\n }),\n animateStickyHeaderTop(false),\n ]);\n }\n\n function animateStickyHeaderTop(isScrollingDown = true) {\n let from = getCssVarValue(element, \"stickyHeaderTop\");\n\n if (!from)\n from = isScrollingDown ? element.offsetHeight : getCollapsedHeaderHeight();\n\n const to = isScrollingDown\n ? getCollapsedHeaderHeight()\n : element.getBoundingClientRect().height;\n\n return animate(from, to, {\n onUpdate: (latest) => updateCssVar(element, \"stickyHeaderTop\", latest),\n });\n }\n};\n"]}
@@ -0,0 +1,6 @@
1
+ import * as gnavHeader_js from './gnav-header.js';
2
+ export { gnavHeader_js as GnavHeader };
3
+ import * as gnavHeaderSection_js from './gnav-header-section.js';
4
+ export { gnavHeaderSection_js as GnavHeaderSection };
5
+ //# sourceMappingURL=index.js.map
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js","sourcesContent":[]}
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,29 @@
1
+ // Generated by dts-bundle-generator v9.5.1
2
+
3
+ import { ICustomElement } from 'component-register';
4
+
5
+ export type CorrectComponentOptions = {
6
+ element: HTMLElement & ICustomElement;
7
+ };
8
+ export type CorrectComponentType<T> = (props: T, options: CorrectComponentOptions) => unknown;
9
+ export type Props = {
10
+ scrollThreshold: number;
11
+ collapsed: boolean;
12
+ };
13
+ declare const Name = "gnav-header";
14
+ declare const Component: CorrectComponentType<Props>;
15
+ type Props$1 = {
16
+ shouldTrigger: boolean;
17
+ position: number;
18
+ hideOnTrigger: boolean;
19
+ };
20
+ declare const Name$1 = "gnav-header-section";
21
+ declare const Component$1: CorrectComponentType<Props$1>;
22
+ export type GnavHeaderProps = Props;
23
+ export type GnavHeaderSectionProps = GnavHeaderSection.Props;
24
+
25
+ declare namespace GnavHeaderSection {
26
+ export { Component$1 as Component, Name$1 as Name, Props$1 as Props };
27
+ }
28
+
29
+ export {};
@@ -0,0 +1,18 @@
1
+ import { customShadowlessElement, correctElementType } from '@brytdesigns/web-component-core/utils';
2
+ import { GnavHeader, GnavHeaderSection } from './components/index.js';
3
+
4
+ customShadowlessElement(
5
+ GnavHeader.Name,
6
+ {
7
+ scrollThreshold: 20,
8
+ collapsed: false
9
+ },
10
+ correctElementType(GnavHeader.Component)
11
+ );
12
+ customShadowlessElement(GnavHeaderSection.Name, {
13
+ hideOnTrigger: false,
14
+ position: 0,
15
+ shouldTrigger: false
16
+ }, correctElementType(GnavHeaderSection.Component));
17
+ //# sourceMappingURL=index.js.map
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/index.ts"],"names":[],"mappings":";;;AAUA,uBAAA;AAAA,EACC,UAAW,CAAA,IAAA;AAAA,EACX;AAAA,IACC,eAAiB,EAAA,EAAA;AAAA,IACjB,SAAW,EAAA;AAAA,GACZ;AAAA,EACA,kBAAA,CAAmB,WAAW,SAAS;AACxC,CAAA;AAEA,uBAAA,CAAwB,kBAAkB,IAAM,EAAA;AAAA,EAC/C,aAAe,EAAA,KAAA;AAAA,EACf,QAAU,EAAA,CAAA;AAAA,EACV,aAAe,EAAA;AAChB,CAAG,EAAA,kBAAA,CAAmB,iBAAkB,CAAA,SAAS,CAAC,CAAA","file":"index.js","sourcesContent":["import {\n\tcorrectElementType,\n\tcustomShadowlessElement,\n} from \"@brytdesigns/web-component-core/utils\";\n\nimport { GnavHeader, GnavHeaderSection } from \"./components/index.js\";\n\nexport type GnavHeaderProps = GnavHeader.Props;\nexport type GnavHeaderSectionProps = GnavHeaderSection.Props;\n\ncustomShadowlessElement(\n\tGnavHeader.Name,\n\t{\n\t\tscrollThreshold: 20,\n\t\tcollapsed: false\n\t},\n\tcorrectElementType(GnavHeader.Component),\n);\n\ncustomShadowlessElement(GnavHeaderSection.Name, {\n\thideOnTrigger: false,\n\tposition: 0,\n\tshouldTrigger: false\n}, correctElementType(GnavHeaderSection.Component))"]}
@@ -0,0 +1,26 @@
1
+ const groupBy = (list, getKey) => list.reduce(
2
+ (previous, currentItem, index) => {
3
+ const group = getKey(currentItem, index);
4
+ if (!previous[group]) previous[group] = [];
5
+ previous[group].push(currentItem);
6
+ return previous;
7
+ },
8
+ {}
9
+ );
10
+ const CSSVars = {
11
+ headerHeight: "--header-height",
12
+ collapsedHeaderHeight: "--collapsed-header-height",
13
+ stickyHeaderHeight: "--sticky-header-height",
14
+ stickyHeaderTop: "--sticky-header-top"
15
+ };
16
+ function updateCssVar(host, varName, amount) {
17
+ host.style.setProperty(CSSVars[varName], `${amount}px`);
18
+ }
19
+ function getCssVarValue(host, varName) {
20
+ const raw = getComputedStyle(host).getPropertyValue(CSSVars[varName]);
21
+ return parseFloat(raw) || 0;
22
+ }
23
+
24
+ export { CSSVars, getCssVarValue, groupBy, updateCssVar };
25
+ //# sourceMappingURL=utils.js.map
26
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils.ts"],"names":[],"mappings":"AAAO,MAAM,OAAU,GAAA,CACrB,IACA,EAAA,MAAA,KAEA,IAAK,CAAA,MAAA;AAAA,EACH,CAAC,QAAU,EAAA,WAAA,EAAa,KAAU,KAAA;AAChC,IAAM,MAAA,KAAA,GAAQ,MAAO,CAAA,WAAA,EAAa,KAAK,CAAA;AACvC,IAAA,IAAI,CAAC,QAAS,CAAA,KAAK,GAAY,QAAA,CAAA,KAAK,IAAI,EAAC;AACzC,IAAS,QAAA,CAAA,KAAK,CAAE,CAAA,IAAA,CAAK,WAAW,CAAA;AAChC,IAAO,OAAA,QAAA;AAAA,GACT;AAAA,EACA;AACF;AAEK,MAAM,OAAU,GAAA;AAAA,EACrB,YAAc,EAAA,iBAAA;AAAA,EACd,qBAAuB,EAAA,2BAAA;AAAA,EACvB,kBAAoB,EAAA,wBAAA;AAAA,EACpB,eAAiB,EAAA;AACnB;AAEO,SAAS,YAAA,CACd,IACA,EAAA,OAAA,EACA,MACA,EAAA;AACA,EAAA,IAAA,CAAK,MAAM,WAAY,CAAA,OAAA,CAAQ,OAAO,CAAG,EAAA,CAAA,EAAG,MAAM,CAAI,EAAA,CAAA,CAAA;AACxD;AAEO,SAAS,cAAA,CACd,MACA,OACQ,EAAA;AACR,EAAA,MAAM,MAAM,gBAAiB,CAAA,IAAI,EAAE,gBAAiB,CAAA,OAAA,CAAQ,OAAO,CAAC,CAAA;AACpE,EAAO,OAAA,UAAA,CAAW,GAAG,CAAK,IAAA,CAAA;AAC5B","file":"utils.js","sourcesContent":["export const groupBy = <T, K extends PropertyKey>(\n list: T[],\n getKey: (item: T, index: number) => K\n) =>\n list.reduce(\n (previous, currentItem, index) => {\n const group = getKey(currentItem, index);\n if (!previous[group]) previous[group] = [];\n previous[group].push(currentItem);\n return previous;\n },\n {} as Record<K, T[]>\n );\n\nexport const CSSVars = {\n headerHeight: \"--header-height\",\n collapsedHeaderHeight: \"--collapsed-header-height\",\n stickyHeaderHeight: \"--sticky-header-height\",\n stickyHeaderTop: \"--sticky-header-top\",\n} as const;\n\nexport function updateCssVar(\n host: HTMLElement,\n varName: keyof typeof CSSVars,\n amount: number\n) {\n host.style.setProperty(CSSVars[varName], `${amount}px`);\n}\n\nexport function getCssVarValue(\n host: HTMLElement,\n varName: keyof typeof CSSVars\n): number {\n const raw = getComputedStyle(host).getPropertyValue(CSSVars[varName]);\n return parseFloat(raw) || 0;\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@brytdesigns/web-component-gnav-header",
3
+ "version": "1.0.0",
4
+ "description": "Web component wrapper for the gnav-header navigation element",
5
+ "main": "./dist/main/index.js",
6
+ "module": "./dist/main/index.js",
7
+ "types": "./dist/main/index.d.ts",
8
+ "type": "module",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/main/index.d.ts",
12
+ "module": "./dist/main/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "keywords": [],
19
+ "author": "Bryt Designs",
20
+ "license": "ISC",
21
+ "dependencies": {
22
+ "@solid-primitives/scheduled": "^1.5.3",
23
+ "component-register": "0.8.7",
24
+ "motion": "^12.40.0",
25
+ "solid-element": "^1.9.1",
26
+ "solid-js": "^1.9.9",
27
+ "@brytdesigns/web-component-core": "1.1.7"
28
+ },
29
+ "devDependencies": {
30
+ "dts-bundle-generator": "^9.5.1",
31
+ "tsup": "^8.4.0"
32
+ },
33
+ "scripts": {
34
+ "build": "tsup --clean",
35
+ "typecheck": "tsc --noEmit"
36
+ }
37
+ }