@studiometa/ui 0.2.4 → 0.2.7

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 (65) 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.cjs +12 -3
  5. package/atoms/Figure/Figure.d.ts +18 -0
  6. package/atoms/Figure/Figure.js +1 -1
  7. package/atoms/Figure/Figure.twig +120 -0
  8. package/atoms/Figure/FigureTwicPics.cjs +72 -0
  9. package/atoms/Figure/FigureTwicPics.d.ts +48 -0
  10. package/atoms/Figure/FigureTwicPics.js +1 -0
  11. package/atoms/Figure/index.cjs +31 -0
  12. package/atoms/Figure/index.d.ts +2 -0
  13. package/atoms/Figure/index.js +1 -0
  14. package/atoms/Icon/Icon.twig +13 -0
  15. package/atoms/LargeText/LargeText.twig +49 -0
  16. package/atoms/ScrollAnimation/AbstractScrollAnimation.cjs +126 -0
  17. package/atoms/ScrollAnimation/AbstractScrollAnimation.d.ts +133 -0
  18. package/atoms/ScrollAnimation/AbstractScrollAnimation.js +1 -0
  19. package/atoms/ScrollAnimation/ScrollAnimation.cjs +51 -0
  20. package/atoms/ScrollAnimation/ScrollAnimation.d.ts +55 -0
  21. package/atoms/ScrollAnimation/ScrollAnimation.js +1 -0
  22. package/atoms/ScrollAnimation/ScrollAnimationChild.cjs +51 -0
  23. package/atoms/ScrollAnimation/ScrollAnimationChild.d.ts +13 -0
  24. package/atoms/ScrollAnimation/ScrollAnimationChild.js +1 -0
  25. package/atoms/ScrollAnimation/ScrollAnimationChildWithEase.cjs +41 -0
  26. package/atoms/ScrollAnimation/ScrollAnimationChildWithEase.d.ts +6 -0
  27. package/atoms/ScrollAnimation/ScrollAnimationChildWithEase.js +1 -0
  28. package/atoms/ScrollAnimation/ScrollAnimationParent.cjs +48 -0
  29. package/atoms/ScrollAnimation/ScrollAnimationParent.d.ts +35 -0
  30. package/atoms/ScrollAnimation/ScrollAnimationParent.js +1 -0
  31. package/atoms/ScrollAnimation/ScrollAnimationWithEase.cjs +41 -0
  32. package/atoms/ScrollAnimation/ScrollAnimationWithEase.d.ts +6 -0
  33. package/atoms/ScrollAnimation/ScrollAnimationWithEase.js +1 -0
  34. package/atoms/ScrollAnimation/animationScrollWithEase.cjs +70 -0
  35. package/atoms/ScrollAnimation/animationScrollWithEase.d.ts +11 -0
  36. package/atoms/ScrollAnimation/animationScrollWithEase.js +1 -0
  37. package/atoms/ScrollAnimation/index.cjs +41 -0
  38. package/atoms/ScrollAnimation/index.d.ts +7 -0
  39. package/atoms/ScrollAnimation/index.js +1 -0
  40. package/atoms/index.cjs +2 -2
  41. package/atoms/index.d.ts +2 -1
  42. package/atoms/index.js +1 -1
  43. package/index.cjs +1 -0
  44. package/index.d.ts +1 -0
  45. package/index.js +1 -1
  46. package/molecules/Accordion/Accordion.twig +54 -0
  47. package/molecules/Modal/Modal.twig +108 -0
  48. package/molecules/Modal/StyledModal.twig +39 -0
  49. package/molecules/Panel/Panel.twig +73 -0
  50. package/molecules/Panel/StyledPanel.twig +28 -0
  51. package/molecules/Slider/Slider.cjs +12 -4
  52. package/molecules/Slider/Slider.d.ts +11 -0
  53. package/molecules/Slider/Slider.js +1 -1
  54. package/molecules/Slider/SliderItem.cjs +5 -4
  55. package/molecules/Slider/SliderItem.d.ts +5 -0
  56. package/molecules/Slider/SliderItem.js +1 -1
  57. package/molecules/Sticky/Sticky.twig +31 -0
  58. package/molecules/Tabs/Tabs.twig +20 -0
  59. package/organisms/Frame/Frame.cjs +40 -1
  60. package/organisms/Frame/Frame.d.ts +34 -1
  61. package/organisms/Frame/Frame.js +1 -1
  62. package/organisms/Frame/FrameTarget.cjs +3 -3
  63. package/organisms/Frame/FrameTarget.js +1 -1
  64. package/organisms/ImageGrid/ImageGrid.twig +42 -0
  65. package/package.json +2 -2
package/atoms/index.cjs CHANGED
@@ -25,15 +25,15 @@ var atoms_exports = {};
25
25
  __export(atoms_exports, {
26
26
  AnchorScrollTo: () => import_AnchorScrollTo.default,
27
27
  Cursor: () => import_Cursor.default,
28
- Figure: () => import_Figure.default,
29
28
  LargeText: () => import_LargeText.default,
30
29
  LazyInclude: () => import_LazyInclude.default
31
30
  });
32
31
  module.exports = __toCommonJS(atoms_exports);
32
+ __reExport(atoms_exports, require("./Figure/index.cjs"), module.exports);
33
33
  __reExport(atoms_exports, require("./Prefetch/index.cjs"), module.exports);
34
+ __reExport(atoms_exports, require("./ScrollAnimation/index.cjs"), module.exports);
34
35
  var import_AnchorScrollTo = __toESM(require("./AnchorScrollTo/AnchorScrollTo.cjs"), 1);
35
36
  var import_Cursor = __toESM(require("./Cursor/Cursor.cjs"), 1);
36
- var import_Figure = __toESM(require("./Figure/Figure.cjs"), 1);
37
37
  var import_LargeText = __toESM(require("./LargeText/LargeText.cjs"), 1);
38
38
  var import_LazyInclude = __toESM(require("./LazyInclude/LazyInclude.cjs"), 1);
39
39
  if (module.exports.default) module.exports = module.exports.default;
package/atoms/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
+ export * from "./Figure/index.js";
1
2
  export * from "./Prefetch/index.js";
3
+ export * from "./ScrollAnimation/index.js";
2
4
  export { default as AnchorScrollTo } from "./AnchorScrollTo/AnchorScrollTo.js";
3
5
  export { default as Cursor } from "./Cursor/Cursor.js";
4
- export { default as Figure } from "./Figure/Figure.js";
5
6
  export { default as LargeText } from "./LargeText/LargeText.js";
6
7
  export { default as LazyInclude } from "./LazyInclude/LazyInclude.js";
package/atoms/index.js CHANGED
@@ -1 +1 @@
1
- export*from"./Prefetch/index.js";import{default as a}from"./AnchorScrollTo/AnchorScrollTo.js";import{default as f}from"./Cursor/Cursor.js";import{default as u}from"./Figure/Figure.js";import{default as d}from"./LargeText/LargeText.js";import{default as p}from"./LazyInclude/LazyInclude.js";export{a as AnchorScrollTo,f as Cursor,u as Figure,d as LargeText,p as LazyInclude};
1
+ export*from"./Figure/index.js";export*from"./Prefetch/index.js";export*from"./ScrollAnimation/index.js";import{default as a}from"./AnchorScrollTo/AnchorScrollTo.js";import{default as l}from"./Cursor/Cursor.js";import{default as p}from"./LargeText/LargeText.js";import{default as d}from"./LazyInclude/LazyInclude.js";export{a as AnchorScrollTo,l as Cursor,p as LargeText,d as LazyInclude};
package/index.cjs CHANGED
@@ -19,4 +19,5 @@ module.exports = __toCommonJS(ui_exports);
19
19
  __reExport(ui_exports, require("./primitives/index.cjs"), module.exports);
20
20
  __reExport(ui_exports, require("./atoms/index.cjs"), module.exports);
21
21
  __reExport(ui_exports, require("./molecules/index.cjs"), module.exports);
22
+ __reExport(ui_exports, require("./organisms/index.cjs"), module.exports);
22
23
  if (module.exports.default) module.exports = module.exports.default;
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 %}
@@ -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};
@@ -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,8 +77,11 @@ var SliderItem = class extends (0, import_js_toolkit.withIntersectionObserver)(i
79
77
  moveInstantly(targetPosition) {
80
78
  this.x = targetPosition;
81
79
  this.dampedX = targetPosition;
80
+ this.render();
81
+ }
82
+ render() {
82
83
  this.$el.style.transform = `${(0, import_utils.matrix)({
83
- translateX: targetPosition
84
+ translateX: this.dampedX
84
85
  })} translateZ(0px)`;
85
86
  }
86
87
  willBeVisible(targetPosition) {
@@ -81,6 +81,11 @@ export default class SliderItem extends Base {
81
81
  * @returns {void}
82
82
  */
83
83
  moveInstantly(targetPosition: number): void;
84
+ /**
85
+ * Render the transform.
86
+ * @returns {void}
87
+ */
88
+ render(): void;
84
89
  /**
85
90
  * Check if SliderItem is partially visible for the given target position.
86
91
  *
@@ -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 i,withIntersectionObserver as s}from"@studiometa/js-toolkit";import{matrix as d,damp as h}from"@studiometa/js-toolkit/utils";class r extends s(i,{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:t}]){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=t}ticked(){this.dampedX=h(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(){this.$el.style.transform=`${d({translateX:this.dampedX})} translateZ(0px)`}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,t=this.$el.getBoundingClientRect().toJSON();this.rect={...t,left:t.left+e,right:t.left+e+t.width,x:t.left+e}}}export{r 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>
@@ -0,0 +1,20 @@
1
+ <div data-component="Tabs" data-option-styles='{ "btn": { "open": { "borderBottomColor": "#fff" } } }'>
2
+ {% block title_wrapper %}
3
+ {% for item in items %}
4
+ <button data-ref="btn[]" style="border-bottom: 1px solid transparent;">
5
+ {% block title %}
6
+ {{ item.title }}
7
+ {% endblock %}
8
+ </button>
9
+ {% endfor %}
10
+ {% endblock %}
11
+ {% block content_wrapper %}
12
+ {% for item in items %}
13
+ <div data-ref="content[]" aria-hidden="false">
14
+ {% block content %}
15
+ {{ item.content }}
16
+ {% endblock %}
17
+ </div>
18
+ {% endfor %}
19
+ {% endblock %}
20
+ </div>
@@ -35,6 +35,12 @@ var import_utils = require("@studiometa/js-toolkit/utils");
35
35
  var import_FrameAnchor = __toESM(require("./FrameAnchor.cjs"), 1);
36
36
  var import_FrameForm = __toESM(require("./FrameForm.cjs"), 1);
37
37
  var import_FrameTarget = __toESM(require("./FrameTarget.cjs"), 1);
38
+ function getScrollPosition() {
39
+ return {
40
+ left: window.pageXOffset,
41
+ top: window.pageYOffset
42
+ };
43
+ }
38
44
  var cache = /* @__PURE__ */ new Map();
39
45
  var _Frame = class extends import_js_toolkit.Base {
40
46
  get id() {
@@ -58,6 +64,35 @@ var _Frame = class extends import_js_toolkit.Base {
58
64
  get directChildFrameTarget() {
59
65
  return this.getDirectChild("FrameTarget");
60
66
  }
67
+ mounted() {
68
+ if (this.$options.history) {
69
+ window.addEventListener("popstate", this);
70
+ }
71
+ }
72
+ destroyed() {
73
+ window.removeEventListener("popstate", this);
74
+ }
75
+ handleEvent(event) {
76
+ if (event.type === "popstate") {
77
+ this.onWindowPopstate(event);
78
+ }
79
+ if (event.type === "beforeunload") {
80
+ this.onWindowUnload();
81
+ }
82
+ }
83
+ onWindowUnload() {
84
+ const { history } = window;
85
+ if (!history.state) {
86
+ return;
87
+ }
88
+ history.replaceState({
89
+ ...history.state,
90
+ scroll: getScrollPosition()
91
+ }, "");
92
+ }
93
+ onWindowPopstate(event) {
94
+ this.goTo(window.location.href, event.state);
95
+ }
61
96
  onFrameAnchorFrameClick(event, index) {
62
97
  if (!this.directChildFrameAnchor.includes(this.$children.FrameAnchor[index])) {
63
98
  return;
@@ -82,7 +117,7 @@ var _Frame = class extends import_js_toolkit.Base {
82
117
  parseHTML(string = "") {
83
118
  return new DOMParser().parseFromString(string, "text/html");
84
119
  }
85
- async goTo(url) {
120
+ async goTo(url, scroll = null) {
86
121
  this.$log("goTo", url);
87
122
  const parsedUrl = new URL(url);
88
123
  if (parsedUrl.origin !== window.location.origin) {
@@ -104,6 +139,10 @@ var _Frame = class extends import_js_toolkit.Base {
104
139
  document.title = doc.title;
105
140
  (0, import_utils.historyPush)({ path: parsedUrl.pathname, search: parsedUrl.searchParams });
106
141
  }
142
+ if (scroll) {
143
+ document.scrollingElement.scrollTop = scroll.top;
144
+ document.scrollingElement.scrollLeft = scroll.left;
145
+ }
107
146
  await (0, import_utils.nextFrame)();
108
147
  this.$root.$update();
109
148
  await (0, import_utils.nextFrame)();
@@ -63,6 +63,35 @@ export default class Frame extends Base {
63
63
  * @returns {FrameTarget[]}
64
64
  */
65
65
  get directChildFrameTarget(): FrameTarget[];
66
+ /**
67
+ * Mounted hook.
68
+ * @returns {void}
69
+ */
70
+ mounted(): void;
71
+ /**
72
+ * Destroyed hook.
73
+ * @returns {void}
74
+ */
75
+ destroyed(): void;
76
+ /**
77
+ * Dispatch events.
78
+ * @param {PopStateEvent} event
79
+ * @returns {void}
80
+ */
81
+ handleEvent(event: PopStateEvent): void;
82
+ /**
83
+ * Prevent scroll top on unload.
84
+ *
85
+ * @returns {void}
86
+ */
87
+ onWindowUnload(): void;
88
+ /**
89
+ * Go to the previous URL on `popstate` event.
90
+ *
91
+ * @param {PopStateEvent} event
92
+ * @returns {void}
93
+ */
94
+ onWindowPopstate(event: PopStateEvent): void;
66
95
  /**
67
96
  * Prevent click on `FrameAnchor`.
68
97
  *
@@ -90,9 +119,13 @@ export default class Frame extends Base {
90
119
  /**
91
120
  * Go to the given url.
92
121
  * @param {string} url
122
+ * @param {null|{ top: number, left: number }} [scroll]
93
123
  * @returns {Promise<void>}
94
124
  */
95
- goTo(url: string): Promise<void>;
125
+ goTo(url: string, scroll?: null | {
126
+ top: number;
127
+ left: number;
128
+ }): Promise<void>;
96
129
  /**
97
130
  * Fetch the given url.
98
131
  * @param {string} url