@studiometa/ui 0.2.5 → 0.2.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.
Files changed (50) hide show
  1. package/atoms/Button/Button.twig +68 -0
  2. package/atoms/Button/StyledButton.twig +47 -0
  3. package/atoms/Cursor/Cursor.twig +28 -0
  4. package/atoms/Figure/Figure.twig +120 -0
  5. package/atoms/Icon/Icon.twig +13 -0
  6. package/atoms/LargeText/LargeText.cjs +3 -3
  7. package/atoms/LargeText/LargeText.d.ts +1 -2
  8. package/atoms/LargeText/LargeText.js +1 -1
  9. package/atoms/LargeText/LargeText.twig +49 -0
  10. package/atoms/ScrollAnimation/AbstractScrollAnimation.cjs +18 -59
  11. package/atoms/ScrollAnimation/AbstractScrollAnimation.d.ts +28 -55
  12. package/atoms/ScrollAnimation/AbstractScrollAnimation.js +1 -1
  13. package/atoms/ScrollAnimation/ScrollAnimation.d.ts +9 -4
  14. package/atoms/ScrollAnimation/animationScrollWithEase.cjs +3 -24
  15. package/atoms/ScrollAnimation/animationScrollWithEase.js +1 -1
  16. package/index.cjs +1 -0
  17. package/index.d.ts +1 -0
  18. package/index.js +1 -1
  19. package/molecules/Accordion/Accordion.twig +54 -0
  20. package/molecules/Modal/Modal.twig +108 -0
  21. package/molecules/Modal/StyledModal.twig +39 -0
  22. package/molecules/Panel/Panel.twig +73 -0
  23. package/molecules/Panel/StyledPanel.twig +28 -0
  24. package/molecules/Slider/AbstractSliderChild.cjs +8 -1
  25. package/molecules/Slider/AbstractSliderChild.d.ts +2 -2
  26. package/molecules/Slider/AbstractSliderChild.js +1 -1
  27. package/molecules/Slider/Slider.cjs +12 -4
  28. package/molecules/Slider/Slider.d.ts +11 -0
  29. package/molecules/Slider/Slider.js +1 -1
  30. package/molecules/Slider/SliderBtn.d.ts +8 -0
  31. package/molecules/Slider/SliderCount.d.ts +8 -0
  32. package/molecules/Slider/SliderDots.d.ts +8 -0
  33. package/molecules/Slider/SliderDrag.cjs +5 -1
  34. package/molecules/Slider/SliderDrag.d.ts +7 -0
  35. package/molecules/Slider/SliderDrag.js +1 -1
  36. package/molecules/Slider/SliderItem.cjs +7 -6
  37. package/molecules/Slider/SliderItem.d.ts +9 -0
  38. package/molecules/Slider/SliderItem.js +1 -1
  39. package/molecules/Slider/SliderProgress.cjs +7 -3
  40. package/molecules/Slider/SliderProgress.d.ts +8 -0
  41. package/molecules/Slider/SliderProgress.js +1 -1
  42. package/molecules/Sticky/Sticky.twig +31 -0
  43. package/molecules/Tabs/Tabs.twig +20 -0
  44. package/organisms/Frame/Frame.cjs +44 -3
  45. package/organisms/Frame/Frame.d.ts +34 -1
  46. package/organisms/Frame/Frame.js +1 -1
  47. package/organisms/Frame/FrameTarget.cjs +3 -3
  48. package/organisms/Frame/FrameTarget.js +1 -1
  49. package/organisms/ImageGrid/ImageGrid.twig +42 -0
  50. package/package.json +2 -2
package/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./primitives/index.js";
2
2
  export * from "./atoms/index.js";
3
3
  export * from "./molecules/index.js";
4
+ export * from "./organisms/index.js";
package/index.js CHANGED
@@ -1 +1 @@
1
- export*from"./primitives/index.js";export*from"./atoms/index.js";export*from"./molecules/index.js";
1
+ export*from"./primitives/index.js";export*from"./atoms/index.js";export*from"./molecules/index.js";export*from"./organisms/index.js";
@@ -0,0 +1,54 @@
1
+ {#
2
+ /**
3
+ * @file
4
+ * Accordion component.
5
+ *
6
+ * @param array<{ title: string, content: unknown, attr: array }> $items
7
+ * The items of the accordion.
8
+ * @param array $attr
9
+ * Use it to customize the root element attributes.
10
+ * @param array $item_attr
11
+ * Use it to customize each item element attributes.
12
+ * @param array $item_container_attr
13
+ * Use it to customize each item container element attributes.
14
+ *
15
+ * @block $title
16
+ * Use it to customize each item's title.
17
+ * @block $content
18
+ * Use it to customize each item's content.
19
+ */
20
+ #}
21
+
22
+ {% set attributes = merge_html_attributes(attr ?? null, { data_component: 'Accordion' }) %}
23
+
24
+ <div {{ html_attributes(attributes) }}>
25
+ {% for item in items %}
26
+ {% set item_attributes = merge_html_attributes(item_attr ?? null, { data_component: 'AccordionItem' }, item.attr ?? null) %}
27
+ {% set is_open = item_attributes.data_option_is_open ?? false %}
28
+ <div {{ html_attributes(item_attributes) }}>
29
+ <button data-ref="btn" class="block w-full" aria-expanded="{{ is_open ? 'true' : 'false' }}">
30
+ {% block title %}
31
+ {{ item.title }}
32
+ {% endblock %}
33
+ </button>
34
+ {% set item_container_attributes =
35
+ merge_html_attributes(
36
+ item_container_attr ?? null,
37
+ {},
38
+ {
39
+ data_ref: 'container',
40
+ style: { visibility: is_open ? '' : 'hidden', height: is_open ? '' : '0' },
41
+ class: 'relative overflow-hidden'
42
+ }
43
+ )
44
+ %}
45
+ <div {{ html_attributes(item_container_attributes) }}>
46
+ <div data-ref="content" aria-hidden="true">
47
+ {% block content %}
48
+ {{ item.content }}
49
+ {% endblock %}
50
+ </div>
51
+ </div>
52
+ </div>
53
+ {% endfor %}
54
+ </div>
@@ -0,0 +1,108 @@
1
+ {#
2
+ /**
3
+ * @file
4
+ * Modal component.
5
+ *
6
+ * @param array $attr
7
+ * Use it to customize the root element attributes.
8
+ * @param array $modal_attr
9
+ * Use it to customize the modal element attributes.
10
+ * @param array $overlay_attr
11
+ * Use it to customize the overlay element attributes.
12
+ * @param array $wrapper_attr
13
+ * Use it to customize the wrapper element attributes.
14
+ * @param array $container_atrr
15
+ * Use it to customize the container element attributes.
16
+ * @param array $content_atrr
17
+ * Use it to customize the content element attributes.
18
+ *
19
+ * @block $open
20
+ * Use this block to customize the open trigger button.
21
+ * @block $close
22
+ * Use this block to customize the close trigger button.
23
+ * @block $content
24
+ * Use this block to set the modal's content.
25
+ */
26
+ #}
27
+
28
+ {# Root attributes #}
29
+ {% set attributes = merge_html_attributes(attr ?? null, { data_component: 'Modal' }) %}
30
+
31
+ {# Modal attributes #}
32
+ {% set modal_attributes =
33
+ merge_html_attributes(
34
+ modal_attr ?? null,
35
+ { class: 'z-goku fixed inset-0' },
36
+ {
37
+ data_ref: 'modal',
38
+ role: 'dialog',
39
+ aria_modal: true,
40
+ aria_hidden: true,
41
+ style: { opacity: '0', pointer_events: 'none', visibility: 'hidden' }
42
+ }
43
+ )
44
+ %}
45
+
46
+ {# Overlay attributes #}
47
+ {% set overlay_attributes =
48
+ merge_html_attributes(
49
+ overlay_attr ?? null,
50
+ { class: 'z-under absolute inset-0 bg-black bg-opacity-75' },
51
+ { data_ref: 'overlay', tabindex: '-1' }
52
+ )
53
+ %}
54
+
55
+ {% set wrapper_attributes =
56
+ merge_html_attributes(
57
+ wrapper_attr ?? null,
58
+ { class: 'absolute inset-0 flex items-center justify-center' },
59
+ { class: 'pointer-events-none' }
60
+ )
61
+ %}
62
+
63
+ {# Container attributes #}
64
+ {% set container_attributes =
65
+ merge_html_attributes(
66
+ container_attr ?? null,
67
+ { class: 'bg-white rounded shadow-l' },
68
+ {
69
+ data_ref: 'container',
70
+ class: 'z-above relative max-h-full overflow-x-hidden overflow-y-auto pointer-events-auto'
71
+ }
72
+ )
73
+ %}
74
+
75
+ {# Content attributes #}
76
+ {% set content_attributes =
77
+ merge_html_attributes(
78
+ content_attr ?? null,
79
+ { class: 'max-w-3xl p-16 pt-20' },
80
+ { data_ref: 'content' }
81
+ )
82
+ %}
83
+
84
+ <div {{ html_attributes(attributes) }}>
85
+ {% block open %}
86
+ {% include '@ui/atoms/Button/Button.twig' with { label: 'Open', attr: { data_ref: 'open' } } %}
87
+ {% endblock %}
88
+ <div {{ html_attributes(modal_attributes) }}>
89
+ <div {{ html_attributes(overlay_attributes) }}></div>
90
+ <div {{ html_attributes(wrapper_attributes) }}>
91
+ <div {{ html_attributes(container_attributes) }}>
92
+ {% block close %}
93
+ <div class="absolute top-0 right-0 m-2">
94
+ {% include '@ui/atoms/Button/Button.twig' with {
95
+ label: 'Close',
96
+ attr: { data_ref: 'close' }
97
+ } %}
98
+ </div>
99
+ {% endblock %}
100
+ <div {{ html_attributes(content_attributes) }}>
101
+ {% block content %}
102
+ No content.
103
+ {% endblock %}
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ </div>
@@ -0,0 +1,39 @@
1
+ {#
2
+ /**
3
+ * @file
4
+ * Modal component.
5
+ *
6
+ * @param array $attr
7
+ * Use it to customize the root element attributes.
8
+ * @param array $modal_attr
9
+ * Use it to customize the modal element attributes.
10
+ * @param array $overlay_attr
11
+ * Use it to customize the overlay element attributes.
12
+ * @param array $container_atrr
13
+ * Use it to customize the container element attributes.
14
+ * @param array $content_atrr
15
+ * Use it to customize the content element attributes.
16
+ *
17
+ * @block $open
18
+ * Use this block to customize the open trigger button.
19
+ * @block $close
20
+ * Use this block to customize the close trigger button.
21
+ * @block $content
22
+ * Use this block to set the modal's content.
23
+ */
24
+ #}
25
+
26
+ {% extends '@ui/molecules/Modal/Modal.twig' %}
27
+
28
+ {% block open %}
29
+ {% include '@ui/atoms/Button/StyledButton.twig' with { label: 'Open', attr: { data_ref: 'open' } } %}
30
+ {% endblock %}
31
+
32
+ {% block close %}
33
+ <div class="absolute top-0 right-0 m-2">
34
+ {% include '@ui/atoms/Button/StyledButton.twig' with {
35
+ label: 'Close',
36
+ attr: { data_ref: 'close' }
37
+ } %}
38
+ </div>
39
+ {% endblock %}
@@ -0,0 +1,73 @@
1
+ {#
2
+ /**
3
+ * @file
4
+ * Panel component.
5
+ *
6
+ * @param 'top'|'right'|'bottom'|'left' $position
7
+ * Position of the panel.
8
+ * @param array $wrapper_attr
9
+ * Custom attributes for the wrapper element.
10
+ */
11
+ #}
12
+
13
+ {% extends '@ui/molecules/Modal/Modal.twig' %}
14
+
15
+ {% set position = position ?? 'left' %}
16
+
17
+ {% set attr =
18
+ merge_html_attributes(attr ?? null, { data_component: 'Panel', data_option_position: position })
19
+ %}
20
+
21
+ {% set overlay_attr =
22
+ merge_html_attributes(
23
+ overlay_attr ?? null,
24
+ { class: 'z-under absolute inset-0 bg-black bg-opacity-75' },
25
+ { class: 'transition duration-500 opacity-0' }
26
+ )
27
+ %}
28
+
29
+ {% set wrapper_attr =
30
+ merge_html_attributes(
31
+ wrapper_attr ?? null,
32
+ {},
33
+ {
34
+ class: [
35
+ 'z-above absolute top-0 w-full h-full flex pointer-events-none',
36
+ {
37
+ 'top-0 left-0 items-start justify-center': position == 'top',
38
+ 'top-0 right-0 items-center justify-end': position == 'right',
39
+ 'bottom-0 left-0 items-end justify-center': position == 'bottom',
40
+ 'top-0 left-0 items-center justify-start': position == 'left'
41
+ }
42
+ ]
43
+ }
44
+ )
45
+ %}
46
+
47
+ {% set container_attr =
48
+ merge_html_attributes(
49
+ container_attr ?? null,
50
+ {
51
+ class: [
52
+ 'max-w-2xl',
53
+ {
54
+ 'w-full': position == 'top',
55
+ 'h-full': position == 'right',
56
+ 'w-full': position == 'bottom',
57
+ 'h-full': position == 'left'
58
+ }
59
+ ]
60
+ },
61
+ {
62
+ class: [
63
+ 'transform transition duration-500',
64
+ {
65
+ '-translate-y-full': position == 'top',
66
+ 'translate-x-full': position == 'right',
67
+ 'translate-y-full': position == 'bottom',
68
+ '-translate-x-full': position == 'left'
69
+ }
70
+ ]
71
+ }
72
+ )
73
+ %}
@@ -0,0 +1,28 @@
1
+ {#
2
+ /**
3
+ * @file
4
+ * Panel component.
5
+ *
6
+ * @param 'left'|'right' $position
7
+ * Position of the panel.
8
+ * @param array $wrapper_attr
9
+ * Custom attributes for the wrapper element.
10
+ */
11
+ #}
12
+
13
+ {% extends '@ui/molecules/Panel/Panel.twig' %}
14
+
15
+ {% set container_attr = merge_html_attributes(container_attr ?? null, required={ class: 'bg-white' }) %}
16
+
17
+ {% block open %}
18
+ {% include '@ui/atoms/Button/StyledButton.twig' with { label: 'Open', attr: { data_ref: 'open' } } %}
19
+ {% endblock %}
20
+
21
+ {% block close %}
22
+ <div class="absolute top-0 right-0 m-2">
23
+ {% include '@ui/atoms/Button/StyledButton.twig' with {
24
+ label: 'Close',
25
+ attr: { data_ref: 'close' }
26
+ } %}
27
+ </div>
28
+ {% endblock %}
@@ -51,7 +51,14 @@ var AbstractSliderChild = class extends import_js_toolkit.Base {
51
51
  }
52
52
  handleEvent(event) {
53
53
  if (event.type === "index") {
54
- this.update(event.detail[0]);
54
+ import_utils.domScheduler.read(() => {
55
+ const callback = this.update(event.detail[0]);
56
+ if ((0, import_utils.isFunction)(callback)) {
57
+ import_utils.domScheduler.write(() => {
58
+ callback();
59
+ });
60
+ }
61
+ });
55
62
  }
56
63
  }
57
64
  update(index) {
@@ -45,9 +45,9 @@ export default class AbstractSliderChild extends Base {
45
45
  *
46
46
  * @this {AbstractSliderChildInterface}
47
47
  * @param {number} index The new active index.
48
- * @returns {void}
48
+ * @returns {void|(()=>void)}
49
49
  */
50
- update(this: AbstractSliderChildInterface, index: number): void;
50
+ update(this: AbstractSliderChildInterface, index: number): void | (() => void);
51
51
  }
52
52
  export type AbstractSliderChildInterface = AbstractSliderChild & {
53
53
  $parent: Slider;
@@ -1 +1 @@
1
- import{Base as t}from"@studiometa/js-toolkit";import{nextFrame as i}from"@studiometa/js-toolkit/utils";import r from"./Slider.js";class d extends t{static config={name:"AbstractSliderChild"};$parent;mounted(){if(!(this.$parent instanceof r))throw new Error(`The \`${this.$options.name}\` component must be a direct child of a \`Slider\` component.`);this.$parent.$on("index",this)}resized(){i(()=>{this.update(this.$parent.currentIndex)})}destroyed(){this.$parent.$off("index",this)}handleEvent(e){e.type==="index"&&this.update(e.detail[0])}update(e){throw new Error(`The \`AbstractSliderChild.update(${e})\` method must be implemented.`)}}export{d as default};
1
+ import{Base as r}from"@studiometa/js-toolkit";import{nextFrame as d,domScheduler as i,isFunction as n}from"@studiometa/js-toolkit/utils";import o from"./Slider.js";class a extends r{static config={name:"AbstractSliderChild"};$parent;mounted(){if(!(this.$parent instanceof o))throw new Error(`The \`${this.$options.name}\` component must be a direct child of a \`Slider\` component.`);this.$parent.$on("index",this)}resized(){d(()=>{this.update(this.$parent.currentIndex)})}destroyed(){this.$parent.$off("index",this)}handleEvent(e){e.type==="index"&&i.read(()=>{const t=this.update(e.detail[0]);n(t)&&i.write(()=>{t()})})}update(e){throw new Error(`The \`AbstractSliderChild.update(${e})\` method must be implemented.`)}}export{a as default};
@@ -48,6 +48,11 @@ var Slider = class extends import_js_toolkit.Base {
48
48
  this.currentSliderItem.activate();
49
49
  }
50
50
  states = [];
51
+ origins = {
52
+ left: 0,
53
+ center: 0,
54
+ right: 0
55
+ };
51
56
  get currentState() {
52
57
  return this.states[this.currentIndex];
53
58
  }
@@ -72,7 +77,7 @@ var Slider = class extends import_js_toolkit.Base {
72
77
  getStates() {
73
78
  const { wrapper } = this.$refs;
74
79
  const originRect = wrapper.getBoundingClientRect();
75
- const origins = {
80
+ this.origins = {
76
81
  left: originRect.left,
77
82
  center: originRect.x + originRect.width / 2,
78
83
  right: originRect.x + originRect.width
@@ -80,13 +85,16 @@ var Slider = class extends import_js_toolkit.Base {
80
85
  return this.$children.SliderItem.map((item) => {
81
86
  return {
82
87
  x: {
83
- left: (item.rect.x - origins.left) * -1,
84
- center: (item.rect.x + item.rect.width / 2 - origins.center) * -1,
85
- right: (item.rect.x + item.rect.width - origins.right) * -1
88
+ left: (item.rect.x - this.origins.left) * -1,
89
+ center: (item.rect.x + item.rect.width / 2 - this.origins.center) * -1,
90
+ right: (item.rect.x + item.rect.width - this.origins.right) * -1
86
91
  }
87
92
  };
88
93
  });
89
94
  }
95
+ getOriginByMode(mode) {
96
+ return this.origins[mode ?? this.$options.mode];
97
+ }
90
98
  getStateValueByMode(state, mode) {
91
99
  return state[mode ?? this.$options.mode];
92
100
  }
@@ -75,6 +75,11 @@ export default class Slider extends Base {
75
75
  * @type {SliderState[]}
76
76
  */
77
77
  states: SliderState[];
78
+ /**
79
+ * Origins for the different modes.
80
+ * @type {Record<SliderModes, number>}
81
+ */
82
+ origins: Record<SliderModes, number>;
78
83
  /**
79
84
  * Get the current state.
80
85
  * @returns {SliderState}
@@ -127,6 +132,12 @@ export default class Slider extends Base {
127
132
  right: number;
128
133
  };
129
134
  }[];
135
+ /**
136
+ * Get an origin by mode.
137
+ * @param {SliderOptions['mode']} [mode]
138
+ * @returns {number}
139
+ */
140
+ getOriginByMode(mode?: SliderOptions['mode']): number;
130
141
  /**
131
142
  * Get a state value according to the given mode.
132
143
  *
@@ -1 +1 @@
1
- import{Base as o}from"@studiometa/js-toolkit";import{clamp as d,inertiaFinalValue as c,nextFrame as h}from"@studiometa/js-toolkit/utils";import u from"./SliderDrag.js";import x from"./SliderItem.js";class I extends o{static config={name:"Slider",refs:["wrapper"],emits:["goto","index"],components:{SliderItem:x,SliderDrag:u},options:{mode:{type:String,default:"left"},fitBounds:Boolean,contain:Boolean,sensitivity:{type:Number,default:1}}};__distanceX=0;__initialX=0;__currentIndex=0;get currentIndex(){return this.__currentIndex}set currentIndex(e){this.currentSliderItem.disactivate(),this.$emit("index",e),this.__currentIndex=e,this.currentSliderItem.activate()}states=[];get currentState(){return this.states[this.currentIndex]}get firstState(){return this.states[0]}get lastState(){return this.states[this.states.length-1]}get containMinState(){return this.getStateValueByMode(this.firstState.x,"left")}get containMaxState(){return this.getStateValueByMode(this.lastState.x,"right")}get indexMax(){return this.$children.SliderItem.length-1}get currentSliderItem(){return this.$children.SliderItem[this.currentIndex]}getStates(){const{wrapper:e}=this.$refs,t=e.getBoundingClientRect(),s={left:t.left,center:t.x+t.width/2,right:t.x+t.width};return this.$children.SliderItem.map(i=>({x:{left:(i.rect.x-s.left)*-1,center:(i.rect.x+i.rect.width/2-s.center)*-1,right:(i.rect.x+i.rect.width-s.right)*-1}}))}getStateValueByMode(e,t){return e[t??this.$options.mode]}mounted(){this.states=this.getStates(),this.prepareInvisibleItems(),this.goTo(this.currentIndex)}resized(){h(()=>{this.states=this.getStates(),h(()=>{this.prepareInvisibleItems(),this.goTo(this.currentIndex)})})}goNext(){this.currentIndex+1>this.indexMax||this.goTo(this.currentIndex+1)}goPrev(){this.currentIndex-1<0||this.goTo(this.currentIndex-1)}goTo(e){if(e<0||e>this.indexMax)throw new Error("Index out of bound.");let t=this.getStateValueByMode(this.states[e].x);this.$options.contain&&(this.$children.SliderItem[this.indexMax].willBeFullyVisible(t)?t=this.getStateValueByMode(this.lastState.x,"right"):this.$children.SliderItem[0].willBeFullyVisible(t)&&(t=this.getStateValueByMode(this.firstState.x,"left")));const s=this.getVisibleItems(t);e<this.currentIndex&&s.reverse(),s.forEach(i=>{h(()=>i.move(t))}),this.currentIndex=e,this.$emit("goto",e)}onSliderDragStart(){this.__initialX=this.currentSliderItem?this.currentSliderItem.x:0}onSliderDragDrag(e){Math.abs(e.delta.y)>Math.abs(e.delta.x)||(this.__distanceX=this.__initialX+e.distance.x*this.$options.sensitivity,this.getVisibleItems(this.__distanceX).forEach(t=>{t.moveInstantly(this.__distanceX)}))}onSliderDragDrop(e){if(Math.abs(e.delta.y)>Math.abs(e.delta.x))return;let t=d(c(this.__distanceX,e.delta.x*this.$options.sensitivity),0,this.getStateValueByMode(this.lastState.x));const s=this.states.map(n=>Math.abs(t-this.getStateValueByMode(n.x))),i=Math.min(...s),r=s.findIndex(n=>n===i);this.$options.fitBounds?this.goTo(r):(this.$options.contain&&(t=Math.min(this.containMinState,t),t=Math.max(this.containMaxState,t)),this.$children.SliderItem.forEach(n=>{n.move(t)}),this.currentIndex=r)}prepareInvisibleItems(){const e=this.states[this.currentIndex],t=[],s=[];this.getInvisibleItems(this.getStateValueByMode(e.x)).forEach((i,r)=>{if(r>this.currentIndex){t.push(i);return}r<this.currentIndex&&s.push(i)}),t.forEach(i=>{const r=this.getStateWhereItemWillBeInvisible(i);r&&i.moveInstantly(this.getStateValueByMode(r.x))}),s.forEach(i=>{const r=this.getStateWhereItemWillBeInvisible(i,{reversed:!0});r&&i.moveInstantly(this.getStateValueByMode(r.x))})}getStateWhereItemWillBeInvisible(e,{reversed:t=!1}={}){const s=this.states.filter(a=>e.willBeVisible(this.getStateValueByMode(a.x))),i=s[0],r=s[s.length-1],n=this.states.findIndex(a=>this.getStateValueByMode(a.x)===this.getStateValueByMode(i.x)),l=this.states.findIndex(a=>a.x===r.x);return t?this.states[l+1]:this.states[n-1]}getVisibleItems(e){return this.$children.SliderItem.filter(t=>t.isVisible||t.willBeVisible(e))}getInvisibleItems(e){return this.$children.SliderItem.filter(t=>!t.isVisible&&!t.willBeVisible(e))}}export{I as default};
1
+ import{Base as o}from"@studiometa/js-toolkit";import{clamp as d,inertiaFinalValue as c,nextFrame as h}from"@studiometa/js-toolkit/utils";import u from"./SliderDrag.js";import g from"./SliderItem.js";class x extends o{static config={name:"Slider",refs:["wrapper"],emits:["goto","index"],components:{SliderItem:g,SliderDrag:u},options:{mode:{type:String,default:"left"},fitBounds:Boolean,contain:Boolean,sensitivity:{type:Number,default:1}}};__distanceX=0;__initialX=0;__currentIndex=0;get currentIndex(){return this.__currentIndex}set currentIndex(e){this.currentSliderItem.disactivate(),this.$emit("index",e),this.__currentIndex=e,this.currentSliderItem.activate()}states=[];origins={left:0,center:0,right:0};get currentState(){return this.states[this.currentIndex]}get firstState(){return this.states[0]}get lastState(){return this.states[this.states.length-1]}get containMinState(){return this.getStateValueByMode(this.firstState.x,"left")}get containMaxState(){return this.getStateValueByMode(this.lastState.x,"right")}get indexMax(){return this.$children.SliderItem.length-1}get currentSliderItem(){return this.$children.SliderItem[this.currentIndex]}getStates(){const{wrapper:e}=this.$refs,t=e.getBoundingClientRect();return this.origins={left:t.left,center:t.x+t.width/2,right:t.x+t.width},this.$children.SliderItem.map(i=>({x:{left:(i.rect.x-this.origins.left)*-1,center:(i.rect.x+i.rect.width/2-this.origins.center)*-1,right:(i.rect.x+i.rect.width-this.origins.right)*-1}}))}getOriginByMode(e){return this.origins[e??this.$options.mode]}getStateValueByMode(e,t){return e[t??this.$options.mode]}mounted(){this.states=this.getStates(),this.prepareInvisibleItems(),this.goTo(this.currentIndex)}resized(){h(()=>{this.states=this.getStates(),h(()=>{this.prepareInvisibleItems(),this.goTo(this.currentIndex)})})}goNext(){this.currentIndex+1>this.indexMax||this.goTo(this.currentIndex+1)}goPrev(){this.currentIndex-1<0||this.goTo(this.currentIndex-1)}goTo(e){if(e<0||e>this.indexMax)throw new Error("Index out of bound.");let t=this.getStateValueByMode(this.states[e].x);this.$options.contain&&(this.$children.SliderItem[this.indexMax].willBeFullyVisible(t)?t=this.getStateValueByMode(this.lastState.x,"right"):this.$children.SliderItem[0].willBeFullyVisible(t)&&(t=this.getStateValueByMode(this.firstState.x,"left")));const i=this.getVisibleItems(t);e<this.currentIndex&&i.reverse(),i.forEach(s=>{h(()=>s.move(t))}),this.currentIndex=e,this.$emit("goto",e)}onSliderDragStart(){this.__initialX=this.currentSliderItem?this.currentSliderItem.x:0}onSliderDragDrag(e){Math.abs(e.delta.y)>Math.abs(e.delta.x)||(this.__distanceX=this.__initialX+e.distance.x*this.$options.sensitivity,this.getVisibleItems(this.__distanceX).forEach(t=>{t.moveInstantly(this.__distanceX)}))}onSliderDragDrop(e){if(Math.abs(e.delta.y)>Math.abs(e.delta.x))return;let t=d(c(this.__distanceX,e.delta.x*this.$options.sensitivity),0,this.getStateValueByMode(this.lastState.x));const i=this.states.map(n=>Math.abs(t-this.getStateValueByMode(n.x))),s=Math.min(...i),r=i.findIndex(n=>n===s);this.$options.fitBounds?this.goTo(r):(this.$options.contain&&(t=Math.min(this.containMinState,t),t=Math.max(this.containMaxState,t)),this.$children.SliderItem.forEach(n=>{n.move(t)}),this.currentIndex=r)}prepareInvisibleItems(){const e=this.states[this.currentIndex],t=[],i=[];this.getInvisibleItems(this.getStateValueByMode(e.x)).forEach((s,r)=>{if(r>this.currentIndex){t.push(s);return}r<this.currentIndex&&i.push(s)}),t.forEach(s=>{const r=this.getStateWhereItemWillBeInvisible(s);r&&s.moveInstantly(this.getStateValueByMode(r.x))}),i.forEach(s=>{const r=this.getStateWhereItemWillBeInvisible(s,{reversed:!0});r&&s.moveInstantly(this.getStateValueByMode(r.x))})}getStateWhereItemWillBeInvisible(e,{reversed:t=!1}={}){const i=this.states.filter(a=>e.willBeVisible(this.getStateValueByMode(a.x))),s=i[0],r=i[i.length-1],n=this.states.findIndex(a=>this.getStateValueByMode(a.x)===this.getStateValueByMode(s.x)),l=this.states.findIndex(a=>a.x===r.x);return t?this.states[l+1]:this.states[n-1]}getVisibleItems(e){return this.$children.SliderItem.filter(t=>t.isVisible||t.willBeVisible(e))}getInvisibleItems(e){return this.$children.SliderItem.filter(t=>!t.isVisible&&!t.willBeVisible(e))}}export{x as default};
@@ -17,6 +17,14 @@ export default class SliderBtn extends AbstractSliderChild {
17
17
  next: BooleanConstructor;
18
18
  };
19
19
  };
20
+ /**
21
+ * Update attributes.
22
+ *
23
+ * @this {SliderBtnInterface}
24
+ * @param {number} index
25
+ * @returns {void}
26
+ */
27
+ update(this: SliderBtnInterface, index: number): void;
20
28
  /**
21
29
  * Go prev or next on click.
22
30
  *
@@ -12,6 +12,14 @@ export default class SliderCount extends AbstractSliderChild {
12
12
  name: string;
13
13
  refs: string[];
14
14
  };
15
+ /**
16
+ * Update the current counter indicator.
17
+ *
18
+ * @this {SliderCountInterface}
19
+ * @param {number} index The new active index.
20
+ * @returns {void}
21
+ */
22
+ update(this: SliderCountInterface, index: number): void;
15
23
  }
16
24
  export type SliderCountInterface = SliderCount & {
17
25
  $refs: {
@@ -16,6 +16,14 @@ export default class SliderDots extends AbstractSliderChild {
16
16
  name: string;
17
17
  refs: string[];
18
18
  };
19
+ /**
20
+ * Update dots classes according to the new index.
21
+ *
22
+ * @this {SliderDotsInterface}
23
+ * @param {number} index
24
+ * @returns {void}
25
+ */
26
+ update(this: SliderDotsInterface, index: number): void;
19
27
  /**
20
28
  * Go to the given index on dot click.
21
29
  *
@@ -35,6 +35,10 @@ var SliderDrag = class extends (0, import_js_toolkit.withDrag)(import_js_toolkit
35
35
  };
36
36
  __publicField(SliderDrag, "config", {
37
37
  name: "SliderDrag",
38
- emits: ["start", "drag", "drop", "inertia", "stop"]
38
+ emits: ["start", "drag", "drop", "inertia", "stop"],
39
+ sensitivity: {
40
+ type: Number,
41
+ default: 1
42
+ }
39
43
  });
40
44
  if (module.exports.default) module.exports = module.exports.default;
@@ -2,9 +2,16 @@
2
2
  * SliderDrag class.
3
3
  */
4
4
  export default class SliderDrag extends Base {
5
+ /**
6
+ * Config.
7
+ */
5
8
  static config: {
6
9
  name: string;
7
10
  emits: string[];
11
+ sensitivity: {
12
+ type: NumberConstructor;
13
+ default: number;
14
+ };
8
15
  };
9
16
  /**
10
17
  * Emit drag events.
@@ -1 +1 @@
1
- import{Base as e,withDrag as a}from"@studiometa/js-toolkit";class r extends a(e){static config={name:"SliderDrag",emits:["start","drag","drop","inertia","stop"]};dragged(t){this.$emit(t.mode,t)}}export{r as default};
1
+ import{Base as e,withDrag as i}from"@studiometa/js-toolkit";class a extends i(e){static config={name:"SliderDrag",emits:["start","drag","drop","inertia","stop"],sensitivity:{type:Number,default:1}};dragged(t){this.$emit(t.mode,t)}}export{a as default};
@@ -57,9 +57,7 @@ var SliderItem = class extends (0, import_js_toolkit.withIntersectionObserver)(i
57
57
  }
58
58
  ticked() {
59
59
  this.dampedX = (0, import_utils.damp)(this.x, this.dampedX, 0.2, 1e-5);
60
- this.$el.style.transform = `${(0, import_utils.matrix)({
61
- translateX: this.dampedX
62
- })} translateZ(0px)`;
60
+ this.render();
63
61
  if (this.dampedX === this.x) {
64
62
  this.$services.disable("ticked");
65
63
  }
@@ -79,9 +77,12 @@ var SliderItem = class extends (0, import_js_toolkit.withIntersectionObserver)(i
79
77
  moveInstantly(targetPosition) {
80
78
  this.x = targetPosition;
81
79
  this.dampedX = targetPosition;
82
- this.$el.style.transform = `${(0, import_utils.matrix)({
83
- translateX: targetPosition
84
- })} translateZ(0px)`;
80
+ this.render();
81
+ }
82
+ render() {
83
+ import_utils.domScheduler.write(() => {
84
+ (0, import_utils.transform)(this.$el, { x: this.dampedX });
85
+ });
85
86
  }
86
87
  willBeVisible(targetPosition) {
87
88
  return this.rect.x + targetPosition < window.innerWidth * 1.5 && this.rect.x + targetPosition + this.rect.width > window.innerWidth * -0.5;
@@ -52,6 +52,9 @@ export default class SliderItem extends Base {
52
52
  /**
53
53
  * Ticked hook.
54
54
  *
55
+ * @todo create AbstractSliderItem with `render` method
56
+ * @todo add state to SliderItem
57
+ * @todo add origin to SliderItem
55
58
  * @returns {void}
56
59
  */
57
60
  ticked(): void;
@@ -81,6 +84,12 @@ export default class SliderItem extends Base {
81
84
  * @returns {void}
82
85
  */
83
86
  moveInstantly(targetPosition: number): void;
87
+ /**
88
+ * Render the component.
89
+ *
90
+ * @returns {void}
91
+ */
92
+ render(): void;
84
93
  /**
85
94
  * Check if SliderItem is partially visible for the given target position.
86
95
  *
@@ -1 +1 @@
1
- import{Base as s,withIntersectionObserver as d}from"@studiometa/js-toolkit";import{matrix as i,damp as h}from"@studiometa/js-toolkit/utils";class l extends d(s,{threshold:[0,1]}){static config={name:"SliderItem",emits:["is-fully-visible","is-partially-visible","is-hidden"]};isVisible=!1;x=0;dampedX=0;mounted(){this.updateRectAdjustedWithX()}resized(){this.updateRectAdjustedWithX()}destroyed(){this.moveInstantly(0)}intersected([{intersectionRatio:t,isIntersecting:e}]){t>=1?(this.$emit("is-fully-visible"),this.$el.setAttribute("aria-hidden","false")):t>0?(this.$emit("is-partially-visible"),this.$el.setAttribute("aria-hidden","true")):(this.$emit("is-hidden"),this.$el.setAttribute("aria-hidden","true")),this.isVisible=e}ticked(){this.dampedX=h(this.x,this.dampedX,.2,1e-5),this.$el.style.transform=`${i({translateX:this.dampedX})} translateZ(0px)`,this.dampedX===this.x&&this.$services.disable("ticked")}activate(){this.$el.classList.add("is-active")}disactivate(){this.$el.classList.remove("is-active")}move(t){this.x=t,this.$services.has("ticked")||this.$services.enable("ticked")}moveInstantly(t){this.x=t,this.dampedX=t,this.$el.style.transform=`${i({translateX:t})} translateZ(0px)`}willBeVisible(t){return this.rect.x+t<window.innerWidth*1.5&&this.rect.x+t+this.rect.width>window.innerWidth*-.5}willBeFullyVisible(t){return this.rect.x+t<window.innerWidth&&this.rect.x+t>0&&this.rect.x+t+this.rect.width<window.innerWidth&&this.rect.x+t+this.rect.width>0}updateRectAdjustedWithX(){const t=this.x*-1,e=this.$el.getBoundingClientRect().toJSON();this.rect={...e,left:e.left+t,right:e.left+t+e.width,x:e.left+t}}}export{l as default};
1
+ import{Base as t,withIntersectionObserver as s}from"@studiometa/js-toolkit";import{damp as d,domScheduler as h,transform as r}from"@studiometa/js-toolkit/utils";class l extends s(t,{threshold:[0,1]}){static config={name:"SliderItem",emits:["is-fully-visible","is-partially-visible","is-hidden"]};isVisible=!1;x=0;dampedX=0;mounted(){this.updateRectAdjustedWithX()}resized(){this.updateRectAdjustedWithX()}destroyed(){this.moveInstantly(0)}intersected([{intersectionRatio:e,isIntersecting:i}]){e>=1?(this.$emit("is-fully-visible"),this.$el.setAttribute("aria-hidden","false")):e>0?(this.$emit("is-partially-visible"),this.$el.setAttribute("aria-hidden","true")):(this.$emit("is-hidden"),this.$el.setAttribute("aria-hidden","true")),this.isVisible=i}ticked(){this.dampedX=d(this.x,this.dampedX,.2,1e-5),this.render(),this.dampedX===this.x&&this.$services.disable("ticked")}activate(){this.$el.classList.add("is-active")}disactivate(){this.$el.classList.remove("is-active")}move(e){this.x=e,this.$services.has("ticked")||this.$services.enable("ticked")}moveInstantly(e){this.x=e,this.dampedX=e,this.render()}render(){h.write(()=>{r(this.$el,{x:this.dampedX})})}willBeVisible(e){return this.rect.x+e<window.innerWidth*1.5&&this.rect.x+e+this.rect.width>window.innerWidth*-.5}willBeFullyVisible(e){return this.rect.x+e<window.innerWidth&&this.rect.x+e>0&&this.rect.x+e+this.rect.width<window.innerWidth&&this.rect.x+e+this.rect.width>0}updateRectAdjustedWithX(){const e=this.x*-1,i=this.$el.getBoundingClientRect().toJSON();this.rect={...i,left:i.left+e,right:i.left+e+i.width,x:i.left+e}}}export{l as default};
@@ -34,9 +34,13 @@ var import_utils = require("@studiometa/js-toolkit/utils");
34
34
  var import_AbstractSliderChild = __toESM(require("./AbstractSliderChild.cjs"), 1);
35
35
  var SliderProgress = class extends import_AbstractSliderChild.default {
36
36
  update(index) {
37
- const unit = this.$refs.progress.clientWidth / this.$parent.indexMax;
38
- this.$refs.progress.style.transform = (0, import_utils.matrix)({
39
- translateX: (0, import_utils.map)(index, 0, this.$parent.indexMax, (this.$refs.progress.clientWidth - unit) * -1, 0)
37
+ import_utils.domScheduler.read(() => {
38
+ const unit = this.$refs.progress.clientWidth / (this.$parent.indexMax + 1);
39
+ import_utils.domScheduler.write(() => {
40
+ this.$refs.progress.style.transform = (0, import_utils.matrix)({
41
+ translateX: (0, import_utils.map)(index, 0, this.$parent.indexMax, (this.$refs.progress.clientWidth - unit) * -1, 0)
42
+ });
43
+ });
40
44
  });
41
45
  }
42
46
  };
@@ -17,6 +17,14 @@ export default class SliderProgress extends AbstractSliderChild {
17
17
  name: string;
18
18
  refs: string[];
19
19
  };
20
+ /**
21
+ * Update the progress indicator.
22
+ *
23
+ * @this {SliderProgressInterface}
24
+ * @param {number} index The new active index.
25
+ * @returns {void}
26
+ */
27
+ update(this: SliderProgressInterface, index: number): void;
20
28
  }
21
29
  export type SliderProgressInterface = SliderProgress & {
22
30
  $refs: {
@@ -1 +1 @@
1
- import{matrix as t,map as e}from"@studiometa/js-toolkit/utils";import i from"./AbstractSliderChild.js";class a extends i{static config={name:"SliderProgress",refs:["progress"]};update(r){const s=this.$refs.progress.clientWidth/this.$parent.indexMax;this.$refs.progress.style.transform=t({translateX:e(r,0,this.$parent.indexMax,(this.$refs.progress.clientWidth-s)*-1,0)})}}export{a as default};
1
+ import{matrix as t,map as i,domScheduler as r}from"@studiometa/js-toolkit/utils";import a from"./AbstractSliderChild.js";class o extends a{static config={name:"SliderProgress",refs:["progress"]};update(e){r.read(()=>{const s=this.$refs.progress.clientWidth/(this.$parent.indexMax+1);r.write(()=>{this.$refs.progress.style.transform=t({translateX:i(e,0,this.$parent.indexMax,(this.$refs.progress.clientWidth-s)*-1,0)})})})}}export{o as default};
@@ -0,0 +1,31 @@
1
+ {#
2
+ /**
3
+ * @file
4
+ * Sticky component.
5
+ *
6
+ * @param array $attr
7
+ * Custom attributes for the root element.
8
+ * @param array $innner_attr
9
+ * Custom attributes for the inner element.
10
+ *
11
+ * @block $content
12
+ * Use this block to set the content of the sticky element.
13
+ */
14
+ #}
15
+
16
+ {% set default_attributes = { data_component: 'Sticky', class: 'z-10 sticky top-0 w-full' } %}
17
+ {% set attributes = attr|default({})|merge_html_attributes(default_attributes) %}
18
+
19
+ {% set default_inner_attributes = { data_ref: 'inner', class:'transition duration-500 ease-out-expo' } %}
20
+ {% set inner_attributes = inner_attr|default({})|merge_html_attributes(default_inner_attributes) %}
21
+
22
+ <div {{ html_attributes(attributes) }}>
23
+ <div data-ref="sentinelRef"
24
+ data-component="Sentinel"
25
+ class="absolute bottom-full w-full h-px pointer-events-none"></div>
26
+ <div {{ html_attributes(inner_attributes) }}>
27
+ {% block content %}
28
+ {{ content ?? '' }}
29
+ {% endblock %}
30
+ </div>
31
+ </div>