@unlk/keymaster 1.4.6 → 1.4.8

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,43 @@
1
+ import BaseComponent from 'bootstrap/js/src/base-component.js';
2
+ import EventHandler from 'bootstrap/js/src/dom/event-handler.js';
3
+ import SelectorEngine from 'bootstrap/js/src/dom/selector-engine.js';
4
+ import { defineJQueryPlugin } from 'bootstrap/js/src/util/index.js';
5
+
6
+ const NAME = 'accordionScroll';
7
+ const EVENT_SHOWN = 'shown.bs.collapse';
8
+ const SELECTOR_ACCORDION = '.accordion';
9
+ const SELECTOR_ITEM = '.accordion-item';
10
+ const SELECTOR_HEADER = '.accordion-header';
11
+
12
+ class AccordionScroll extends BaseComponent {
13
+ _onShown(e) {
14
+ const item = e.target.closest(SELECTOR_ITEM);
15
+ if (!item) return;
16
+
17
+ const header = SelectorEngine.findOne(SELECTOR_HEADER, item);
18
+ if (!header) return;
19
+
20
+ const rect = header.getBoundingClientRect();
21
+ if (rect.top < 0) {
22
+ header.scrollIntoView({ behavior: 'smooth', block: 'start' });
23
+ }
24
+ }
25
+
26
+ static get NAME() {
27
+ return NAME;
28
+ }
29
+
30
+ static jQueryInterface(config) {
31
+ return this.each(function () {
32
+ AccordionScroll.getOrCreateInstance(this, config);
33
+ });
34
+ }
35
+ }
36
+
37
+ EventHandler.on(document, EVENT_SHOWN, SELECTOR_ACCORDION, function (e) {
38
+ AccordionScroll.getOrCreateInstance(this)._onShown(e);
39
+ });
40
+
41
+ defineJQueryPlugin(AccordionScroll);
42
+
43
+ export default AccordionScroll;
package/js/bootstrap.js CHANGED
@@ -14,3 +14,4 @@ export { default as Datepicker } from './datepicker';
14
14
  export { default as CarouselCaption } from './carousel-caption';
15
15
  export { default as CarouselHeight } from './carousel-height';
16
16
  export { default as VideoModal } from './video-modal';
17
+ export { default as AccordionScroll } from './accordion-scroll';
package/js/video-modal.js CHANGED
@@ -84,6 +84,13 @@ class VideoModal extends BaseComponent {
84
84
  this._element.dataset.vimeoId = String(vimeoId);
85
85
  this._element.__unlkVimeoPlayer = this._vimeoPlayer;
86
86
 
87
+ this._element.dispatchEvent(
88
+ new CustomEvent('videomodal.ready', {
89
+ bubbles: true,
90
+ detail: { provider: 'vimeo', player: this._vimeoPlayer, videoId: vimeoId }
91
+ })
92
+ );
93
+
87
94
  return;
88
95
  }
89
96
 
@@ -99,6 +106,13 @@ class VideoModal extends BaseComponent {
99
106
 
100
107
  this._element.dataset.ytId = youtubeId;
101
108
  this._element.__unlkYtPlayer = this._youtubePlayer;
109
+
110
+ this._element.dispatchEvent(
111
+ new CustomEvent('videomodal.ready', {
112
+ bubbles: true,
113
+ detail: { provider: 'youtube', player: this._youtubePlayer, videoId: youtubeId }
114
+ })
115
+ );
102
116
  }
103
117
  }
104
118
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unlk/keymaster",
3
- "version": "1.4.6",
3
+ "version": "1.4.8",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
package/react/index.js CHANGED
@@ -2,3 +2,4 @@ export { useDatepicker } from './use-datepicker.js';
2
2
  export { useCarouselCaption } from './use-carousel-caption.js';
3
3
  export { useCarouselHeight } from './use-carousel-height.js';
4
4
  export { useVideoModal } from './use-video-modal.js';
5
+ export { useAccordionScroll } from './use-accordion-scroll.js';
@@ -0,0 +1,36 @@
1
+ import { useCallback } from 'react';
2
+
3
+ /**
4
+ * Replicates accordion-scroll.js behaviour in React.
5
+ *
6
+ * After an accordion panel finishes opening, scrolls its header into view
7
+ * if it has been pushed above the viewport, replacing the Bootstrap
8
+ * shown.bs.collapse event listener.
9
+ *
10
+ * Usage:
11
+ * const { onEntered } = useAccordionScroll();
12
+ * <Accordion>
13
+ * <Accordion.Item eventKey="0">
14
+ * <Accordion.Header>Header</Accordion.Header>
15
+ * <Accordion.Collapse eventKey="0" onEntered={onEntered}>
16
+ * <Accordion.Body>Content</Accordion.Body>
17
+ * </Accordion.Collapse>
18
+ * </Accordion.Item>
19
+ * </Accordion>
20
+ */
21
+ export function useAccordionScroll() {
22
+ const onEntered = useCallback((node) => {
23
+ const item = node.closest('.accordion-item');
24
+ if (!item) return;
25
+
26
+ const header = item.querySelector('.accordion-header');
27
+ if (!header) return;
28
+
29
+ const rect = header.getBoundingClientRect();
30
+ if (rect.top < 0) {
31
+ header.scrollIntoView({ behavior: 'smooth', block: 'start' });
32
+ }
33
+ }, []);
34
+
35
+ return { onEntered };
36
+ }
@@ -73,8 +73,9 @@ function getVimeoId(url) {
73
73
  * show.bs.modal / hidden.bs.modal event listeners.
74
74
  *
75
75
  * @param {object} options
76
- * @param {string} [options.youtubeSrc] - YouTube video URL
77
- * @param {string} [options.vimeoUrl] - Vimeo video URL
76
+ * @param {string} [options.youtubeSrc] - YouTube video URL
77
+ * @param {string} [options.vimeoUrl] - Vimeo video URL
78
+ * @param {function} [options.onReady] - Called with { provider, player, videoId } when the player is ready
78
79
  *
79
80
  * Usage:
80
81
  * const { containerRef, onShow, onHide } = useVideoModal({ youtubeSrc: '...' });
@@ -84,7 +85,7 @@ function getVimeoId(url) {
84
85
  * </div>
85
86
  * </Modal>
86
87
  */
87
- export function useVideoModal({ youtubeSrc, vimeoUrl } = {}) {
88
+ export function useVideoModal({ youtubeSrc, vimeoUrl, onReady } = {}) {
88
89
  const containerRef = useRef(null);
89
90
  const players = useRef({ youtube: null, vimeo: null });
90
91
 
@@ -95,26 +96,36 @@ export function useVideoModal({ youtubeSrc, vimeoUrl } = {}) {
95
96
 
96
97
  if (vimeoUrl) {
97
98
  await loadVimeoAPI();
99
+ const vimeoId = getVimeoId(vimeoUrl);
98
100
 
99
101
  players.current.vimeo = new globalThis.Vimeo.Player(container, {
100
- id: getVimeoId(vimeoUrl),
102
+ id: vimeoId,
101
103
  autoplay: true,
102
104
  });
103
105
 
106
+ if (onReady) {
107
+ onReady({ provider: 'vimeo', player: players.current.vimeo, videoId: vimeoId });
108
+ }
109
+
104
110
  return;
105
111
  }
106
112
 
107
113
  if (youtubeSrc) {
108
114
  await loadYouTubeAPI();
115
+ const youtubeId = getYouTubeId(youtubeSrc);
109
116
 
110
117
  const playerDiv = container.querySelector('[data-yt-player]');
111
118
 
112
119
  players.current.youtube = new globalThis.YT.Player(playerDiv, {
113
- videoId: getYouTubeId(youtubeSrc),
120
+ videoId: youtubeId,
114
121
  playerVars: { autoplay: 1, rel: 0 },
115
122
  });
123
+
124
+ if (onReady) {
125
+ onReady({ provider: 'youtube', player: players.current.youtube, videoId: youtubeId });
126
+ }
116
127
  }
117
- }, [youtubeSrc, vimeoUrl]);
128
+ }, [youtubeSrc, vimeoUrl, onReady]);
118
129
 
119
130
  const onHide = useCallback(() => {
120
131
  if (players.current.vimeo) {
@@ -1,17 +1,38 @@
1
1
  .accordion {
2
- --#{$prefix}accordion-box-shadow: #{$accordion-box-shadow};
3
2
  @include border-radius(var(--#{$prefix}accordion-border-radius));
4
- @include box-shadow(var(--#{$prefix}accordion-box-shadow));
5
- .accordion-button,
3
+ border: 0;
4
+ .accordion-button {
5
+ font-weight: $font-weight-medium;
6
+ &:not(.collapsed) {
7
+ box-shadow: none;
8
+ }
9
+ }
6
10
  .accordion-body {
7
- @extend .fs-1;
11
+ padding-top: 0;
12
+ @extend .fs-4;
13
+ }
14
+ .accordion-item {
15
+ border-top: 0;
16
+ border-right: 0;
17
+ border-left: 0;
18
+ }
19
+ :not(.accordion-alt) .accordion-item:last-child {
20
+ border-bottom: 0;
8
21
  }
9
22
  }
10
23
 
24
+ .accordion-flush {
25
+ --#{$prefix}accordion-box-shadow: #{$accordion-box-shadow};
26
+ @include box-shadow(var(--#{$prefix}accordion-box-shadow));
27
+ @include padding(0 $spacer 0);
28
+ @include border-radius($border-radius);
29
+ }
30
+
11
31
  .accordion-alt {
12
32
  --#{$prefix}accordion-alt-bg: #{$accordion-alt-bg};
13
33
  --#{$prefix}accordion-alt-btn-bg: #{$accordion-alt-button-bg};
14
34
  --#{$prefix}accordion-alt-border-width: #{$accordion-alt-border-width};
35
+ --#{$prefix}accordion-alt-border-active-width: #{$accordion-alt-border-active-width};
15
36
  --#{$prefix}accordion-alt-border-color: #{$accordion-alt-border-color};
16
37
  --#{$prefix}accordion-alt-border-radius: #{$accordion-alt-border-radius};
17
38
  --#{$prefix}accordion-alt-btn-icon-width: #{$accordion-alt-icon-width};
@@ -23,7 +44,7 @@
23
44
 
24
45
  .accordion-button {
25
46
  margin-bottom: 0;
26
- background-color: var(--#{$prefix}accordion-alt-btn-bg);
47
+ background-color: transparent;
27
48
  @include box-shadow(none);
28
49
 
29
50
  i {
@@ -34,7 +55,6 @@
34
55
 
35
56
  &:not(.collapsed) {
36
57
  @include box-shadow(none);
37
- color: var(--#{$prefix}accordion-alt-active-color);
38
58
 
39
59
  &::after {
40
60
  background-image: var(--#{$prefix}accordion-alt-btn-active-icon);
@@ -51,8 +71,19 @@
51
71
 
52
72
  > .accordion-item {
53
73
  background-color: var(--#{$prefix}accordion-alt-bg);
54
- border: var(--#{$prefix}accordion-alt-border-width) solid var(--#{$prefix}accordion-alt-border-color);
74
+ border: var(--#{$prefix}accordion-alt-border-width) solid transparent;
55
75
  @include border-radius(var(--#{$prefix}accordion-alt-border-radius));
76
+ @include transition(var(--#{$prefix}accordion-transition));
77
+ &:hover {
78
+ border-color: var(--#{$prefix}accordion-alt-border-color);
79
+ }
80
+ &:has(.accordion-collapse.show),
81
+ &:has(.accordion-collapse.collapsing) {
82
+ background-color: $white;
83
+ border-color: var(--#{$prefix}accordion-alt-border-color);
84
+ //stylelint-disable-next-line function-disallowed-list
85
+ box-shadow: 0 0 0 calc(var(--#{$prefix}accordion-alt-border-active-width) - var(--#{$prefix}accordion-alt-border-width)) var(--#{$prefix}accordion-alt-border-color);
86
+ }
56
87
 
57
88
  &:not(:last-child) {
58
89
  @include margin-bottom($spacer);
@@ -393,15 +393,17 @@ $border-radius-xxl: 1.5rem !default;
393
393
  $blockquote-font-size: $font-size-base * 3.5 !default;
394
394
 
395
395
  // Accordion
396
- $accordion-bg: $action-25 !default;
397
- $accordion-border-radius: var(--#{$prefix}border-radius-sm) !default;
398
- $accordion-button-bg: var(--#{$prefix}body-bg) !default;
399
- $accordion-button-active-bg: var(--#{$prefix}foundation) !default;
400
- $accordion-button-active-color: var(--#{$prefix}light) !default;
401
- $accordion-icon-color: $body-color !default;
402
- $accordion-icon-active-color: $light !default;
403
- $accordion-button-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='#{$accordion-icon-color}'><path d='M11.1,18.3c0.5,0.5,1.4,0.5,1.9,0L23.6,7.6c0.5-0.5,0.5-1.4,0-1.9c-0.5-0.5-1.4-0.5-1.9,0L12,15.5L2.3,5.7c-0.5-0.5-1.4-0.5-1.9,0s-0.5,1.4,0,1.9L11.1,18.3z'/></svg>") !default;
404
- $accordion-button-active-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='#{$accordion-icon-active-color}'><path d='M11.1,18.3c0.5,0.5,1.4,0.5,1.9,0L23.6,7.6c0.5-0.5,0.5-1.4,0-1.9c-0.5-0.5-1.4-0.5-1.9,0L12,15.5L2.3,5.7c-0.5-0.5-1.4-0.5-1.9,0s-0.5,1.4,0,1.9L11.1,18.3z'/></svg>") !default;
396
+ $accordion-bg: transparent !default;
397
+ $accordion-border-width: .0625rem !default;
398
+ $accordion-border-radius: 0 !default;
399
+ $accordion-button-bg: transparent !default;
400
+ $accordion-button-active-bg: transparent !default;
401
+ $accordion-button-active-color: $body-color !default;
402
+ $accordion-icon-color: $action !default;
403
+ $accordion-icon-active-color: $action !default;
404
+ $accordion-button-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22' fill='#{$accordion-icon-color}'><path d='M12.6923 1.69231C12.6923 0.75625 11.9361 0 11 0C10.0639 0 9.30769 0.75625 9.30769 1.69231V9.30769H1.69231C0.75625 9.30769 0 10.0639 0 11C0 11.9361 0.75625 12.6923 1.69231 12.6923H9.30769V20.3077C9.30769 21.2438 10.0639 22 11 22C11.9361 22 12.6923 21.2438 12.6923 20.3077V12.6923H20.3077C21.2438 12.6923 22 11.9361 22 11C22 10.0639 21.2438 9.30769 20.3077 9.30769H12.6923V1.69231Z'/></svg>") !default;
405
+ $accordion-button-active-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 25' fill='#{$accordion-icon-color}'><path d='M21.2143 12.5C21.2143 13.3643 20.512 14.0625 19.6428 14.0625H2.35713C1.48794 14.0625 0.785706 13.3643 0.785706 12.5C0.785706 11.6357 1.48794 10.9375 2.35713 10.9375H19.6428C20.512 10.9375 21.2143 11.6357 21.2143 12.5Z'/></svg>") !default;
406
+ $accordion-icon-width: 1rem !default;
405
407
  $accordion-button-focus-box-shadow: none !default;
406
408
 
407
409
  // Badges
@@ -8,13 +8,14 @@ $border-radius-xs: rfs-value(4px) !default;
8
8
 
9
9
  // scss-docs-start accordion-variables
10
10
  $accordion-box-shadow: $box-shadow !default;
11
- $accordion-alt-bg: $gray-100 !default;
12
- $accordion-alt-border-width: .125rem !default;
13
- $accordion-alt-border-color: $gray-200 !default;
14
- $accordion-alt-button-bg: $gray-100 !default;
15
- $accordion-alt-icon-width: 1.375rem !default;
11
+ $accordion-alt-bg: $action-50 !default;
12
+ $accordion-alt-border-width: .09375rem !default;
13
+ $accordion-alt-border-active-width: .125rem !default;
14
+ $accordion-alt-border-color: $action !default;
15
+ $accordion-alt-button-bg: $action-50 !default;
16
+ $accordion-alt-icon-width: 1rem !default;
16
17
  $accordion-alt-border-radius: var(--#{$prefix}border-radius-lg) !default;
17
- $accordion-alt-button-active-color: var(--#{$prefix}primary-text-emphasis) !default;
18
+ $accordion-alt-button-active-color: var(--#{$prefix}action) !default;
18
19
  $accordion-alt-button-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22' fill='#{$accordion-icon-color}'><path d='M12.6923 1.69231C12.6923 0.75625 11.9361 0 11 0C10.0639 0 9.30769 0.75625 9.30769 1.69231V9.30769H1.69231C0.75625 9.30769 0 10.0639 0 11C0 11.9361 0.75625 12.6923 1.69231 12.6923H9.30769V20.3077C9.30769 21.2438 10.0639 22 11 22C11.9361 22 12.6923 21.2438 12.6923 20.3077V12.6923H20.3077C21.2438 12.6923 22 11.9361 22 11C22 10.0639 21.2438 9.30769 20.3077 9.30769H12.6923V1.69231Z'/></svg>") !default;
19
20
  $accordion-alt-button-active-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 25' fill='#{$accordion-icon-color}'><path d='M21.2143 12.5C21.2143 13.3643 20.512 14.0625 19.6428 14.0625H2.35713C1.48794 14.0625 0.785706 13.3643 0.785706 12.5C0.785706 11.6357 1.48794 10.9375 2.35713 10.9375H19.6428C20.512 10.9375 21.2143 11.6357 21.2143 12.5Z'/></svg>") !default;
20
21
  // scss-docs-end accordion-variables
@@ -1,2 +1,2 @@
1
1
  // GENERATED FILE – do not edit manually
2
- $km-version: "1.4.6" !default;
2
+ $km-version: "1.4.8" !default;