@trilogy-ds/vanilla 0.0.1-beta.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +82 -0
- package/.prettierrc.js +12 -0
- package/README.md +18 -0
- package/lib/trilogy-ds-vanilla.js +11 -0
- package/package.json +23 -0
- package/src/app.ts +142 -0
- package/src/components/accordion.ts +37 -0
- package/src/components/autocomplete.ts +133 -0
- package/src/components/chips.ts +28 -0
- package/src/components/countdown.ts +40 -0
- package/src/components/font-variant.ts +42 -0
- package/src/components/input-gauge.ts +111 -0
- package/src/components/input-icon.ts +36 -0
- package/src/components/modal.ts +104 -0
- package/src/components/progress-radial.ts +45 -0
- package/src/components/range.ts +48 -0
- package/src/components/segmented-control.ts +16 -0
- package/src/components/select.ts +48 -0
- package/src/components/sticky.ts +14 -0
- package/src/components/table-expansion.ts +11 -0
- package/src/components/tabs.ts +102 -0
- package/src/components/textarea.ts +27 -0
- package/src/utils/intersectionObserver.ts +13 -0
- package/tsconfig.json +10 -0
- package/vite.config.js +23 -0
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
root: true,
|
|
3
|
+
parser: '@typescript-eslint/parser',
|
|
4
|
+
env: {
|
|
5
|
+
node: true,
|
|
6
|
+
},
|
|
7
|
+
plugins: ['@typescript-eslint', 'import', 'jest', 'react', 'react-hooks'],
|
|
8
|
+
extends: [
|
|
9
|
+
'eslint:recommended',
|
|
10
|
+
'plugin:@typescript-eslint/recommended',
|
|
11
|
+
'plugin:import/errors',
|
|
12
|
+
'plugin:import/warnings',
|
|
13
|
+
'plugin:import/typescript',
|
|
14
|
+
'plugin:jest/recommended',
|
|
15
|
+
'plugin:react/recommended',
|
|
16
|
+
'plugin:react-hooks/recommended',
|
|
17
|
+
],
|
|
18
|
+
parserOptions: {
|
|
19
|
+
ecmaFeatures: {
|
|
20
|
+
jsx: true,
|
|
21
|
+
tsx: true,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
rules: {
|
|
25
|
+
'arrow-spacing': 2,
|
|
26
|
+
'block-spacing': 1,
|
|
27
|
+
'brace-style': 1,
|
|
28
|
+
camelcase: ['error', { properties: 'always' }],
|
|
29
|
+
'comma-spacing': 1,
|
|
30
|
+
'comma-style': 1,
|
|
31
|
+
'default-case': 'error',
|
|
32
|
+
'dot-location': ['warn', 'property'],
|
|
33
|
+
'eol-last': 2,
|
|
34
|
+
'func-call-spacing': 2,
|
|
35
|
+
'import/export': 0,
|
|
36
|
+
'jsx-quotes': ['warn', 'prefer-single'],
|
|
37
|
+
'key-spacing': 1,
|
|
38
|
+
'keyword-spacing': 1,
|
|
39
|
+
'lines-between-class-members': 1,
|
|
40
|
+
'max-len': ['error', { code: 170 }],
|
|
41
|
+
'no-alert': 0,
|
|
42
|
+
'no-confusing-arrow': 1,
|
|
43
|
+
'no-console': 0,
|
|
44
|
+
'no-duplicate-imports': 1,
|
|
45
|
+
'no-eval': 2,
|
|
46
|
+
'no-extend-native': 2,
|
|
47
|
+
'no-multiple-empty-lines': [1, { max: 1 }],
|
|
48
|
+
'no-trailing-spaces': 1,
|
|
49
|
+
'no-unneeded-ternary': 1,
|
|
50
|
+
'no-unused-expressions': 0,
|
|
51
|
+
'no-use-before-define': 0,
|
|
52
|
+
'react-hooks/exhaustive-deps': 'off',
|
|
53
|
+
'no-useless-constructor': 1,
|
|
54
|
+
'no-var': 1,
|
|
55
|
+
'object-curly-spacing': [1, 'always'],
|
|
56
|
+
'prefer-const': 1,
|
|
57
|
+
'prefer-destructuring': ['warn', { array: true, object: true }],
|
|
58
|
+
'prefer-rest-params': 1,
|
|
59
|
+
'prefer-spread': 1,
|
|
60
|
+
'prefer-template': 1,
|
|
61
|
+
indent: 'off',
|
|
62
|
+
quotes: 'off',
|
|
63
|
+
'quote-props': ['warn', 'as-needed'],
|
|
64
|
+
'react/display-name': 2,
|
|
65
|
+
'react/jsx-key': 2,
|
|
66
|
+
'react/jsx-no-duplicate-props': 2,
|
|
67
|
+
'react/jsx-no-useless-fragment': 1,
|
|
68
|
+
'react/jsx-no-target-blank': 2,
|
|
69
|
+
'react/prop-types': 0,
|
|
70
|
+
'rest-spread-spacing': 2,
|
|
71
|
+
semi: ['error', 'never', { beforeStatementContinuationChars: 'always' }],
|
|
72
|
+
'spaced-comment': ['warn', 'always'],
|
|
73
|
+
'switch-colon-spacing': 1,
|
|
74
|
+
},
|
|
75
|
+
settings: {
|
|
76
|
+
react: {
|
|
77
|
+
pragma: 'React',
|
|
78
|
+
version: 'detect',
|
|
79
|
+
},
|
|
80
|
+
'import/ignore': ['react-native'],
|
|
81
|
+
},
|
|
82
|
+
}
|
package/.prettierrc.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
bracketSpacing: true,
|
|
3
|
+
jsxBracketSameLine: true,
|
|
4
|
+
jsxSingleQuote: true,
|
|
5
|
+
singleQuote: true,
|
|
6
|
+
trailingComma: 'all',
|
|
7
|
+
semi: false,
|
|
8
|
+
printWidth: 120,
|
|
9
|
+
tabWidth: 2,
|
|
10
|
+
importOrder: ["^react$", "^[A-Za-z-\/]+$", "^[@]", "^[~]", "^[./]",],
|
|
11
|
+
importOrderSeparation: true,
|
|
12
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Trilogy DS Vanilla
|
|
2
|
+
|
|
3
|
+
___
|
|
4
|
+
|
|
5
|
+
This repository contains all the necessary Javascript components to integrate Trilogy Design System in an HTML setting.
|
|
6
|
+
|
|
7
|
+
___
|
|
8
|
+
|
|
9
|
+
## CDN
|
|
10
|
+
|
|
11
|
+
For a faster setup, you can utilize the JSDelivr CDN to include Trilogy Vanilla in your project's HTML:
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<!-- ... -->
|
|
15
|
+
<link href="https://cdn.jsdelivr.net/npm/@trilogy-ds/vanilla" rel="stylesheet" />
|
|
16
|
+
<!-- ... -->
|
|
17
|
+
```
|
|
18
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
(function(A){typeof define=="function"&&define.amd?define(A):A()})(function(){"use strict";const A=()=>{let c=document.querySelectorAll("[data-modal-context]");for(let s=0;s<c.length;s++){let e=c[s],n=e.querySelectorAll("[data-modal-open]"),a=e.querySelector("[data-modal]"),u=e.querySelectorAll("[data-modal-close]"),d=e.querySelectorAll('iframe[src*="www.youtube.com"], iframe[src*="player.vimeo.com"], video');for(let o=0;o<n.length;o++){let f=n[o],m=d[o];f.addEventListener("click",function(){if(i(a),m){if(m.tagName.toLowerCase()==="video"){m.play();return}m.src=m.src+(m.src.indexOf("?")<0?"?":"&")+"autoplay=1"}else return})}for(let o=0;o<u.length;o++)u[o].addEventListener("click",function(){l(a)});t(a);const r=e.querySelector(".modal-background");r&&(r.onclick=function(){l(a)}),e.setAttribute("data-modal-initialized","true")}function t(s){document.addEventListener("keyup",function(e){e=e||window.event;var n=!1;"key"in e?n=e.key==="Escape"||e.key==="Esc":n=e.keyCode===27,n&&l(s)}),document.addEventListener("click",function(e){const n=e.target;let a=n.closest("[data-modal-content]"),u=n.classList.contains("modal");a===null&&u==!0&&l(s)})}const i=s=>{s.classList.add("is-active"),document.body.style.overflow="hidden"},l=s=>{let e=s.querySelector('iframe[src*="youtube"], iframe[src*="vimeo"], video');if(e){if(e.tagName.toLowerCase()==="video"){e.pause();return}e.src=e.src.replace("&autoplay=1","").replace("?autoplay=1","")}s.classList.remove("is-active"),document.body.style.overflow=null}},E=()=>{let c=document.querySelectorAll('[data-variant="auto"]');const t=function(i){let l=0,s=i.length,e=0;if(s>0)for(;e<s;)l=(l<<5)-l+i.charCodeAt(e++)|0;return l};for(let i=0;i<c.length;i++){let l=c[i];const s=l.textContent,e=["b","g","o","q"],n=[];if(s.toLowerCase().split("").map((a,u)=>(e.indexOf(a)>-1&&n.push(u),a)),n.length){const a=t(s),u=Math.abs(a%n.length),d=s.charAt(n[u]),r=s.substring(0,n[u]),o=s.substring(n[u]+1);l.innerHTML=`${r}<span class="has-variant">${d}</span>${o}`}l.setAttribute("data-fontVariant-initialized","true")}},k=()=>{document.querySelectorAll("[data-countdown]").forEach(t=>{let n=t,a=new Date(n.dataset.date).getTime(),u=n.querySelector("[data-days]"),d=n.querySelector("[data-hours]"),r=n.querySelector("[data-minutes]"),o=n.querySelector("[data-seconds]"),f=setInterval(()=>{let m=new Date().getTime(),p=0;a-m>0&&(p=a-m),p<=0&&clearInterval(f),u.innerText=Math.floor(p/864e5).toString(),d.innerText=Math.floor(p%864e5/36e5).toString(),r.innerText=Math.floor(p%36e5/6e4).toString(),o.innerText=Math.floor(p%6e4/1e3).toString()},1e3);n.setAttribute("data-countdown-initialized","true")})},H=c=>{c.length&&c.forEach(t=>{const i=t.querySelector("button.toggle");t.classList.remove("is-active"),i.setAttribute("aria-expanded","false")})},W=c=>{const t=c.querySelectorAll("[data-accordion-context]");t.forEach(i=>{const l=i.querySelector("[data-accordion-toggle]"),s=i.querySelector("button.toggle");l.addEventListener("click",()=>{i.classList.contains("is-disabled")||(i.classList.contains("is-active")?(i.classList.remove("is-active"),s.setAttribute("aria-expanded","false")):(H(t),i.classList.toggle("is-active"),s.setAttribute("aria-expanded","true")))})}),c.setAttribute("data-accordion-initialized","true")},z=()=>{document.querySelectorAll("[data-accordion], .accordions").forEach(t=>{W(t)})},I=()=>{let c=document.querySelectorAll("[data-expandable-row]");for(let t=0;t<c.length;t++){let i=c[t];i.querySelector("[data-expandable-trigger]").addEventListener("click",function(){i.classList.toggle("is-expanded")}),i.setAttribute("data-tableexpansion-initialized","true")}},N=()=>{const c=document.querySelectorAll("[data-tabs-context]"),t=`right: 0;padding-left: 16px;width: 4.5rem !important;background: linear-gradient(90deg, rgba(256,256,256, 0) -25%, white 30%);
|
|
2
|
+
background-attachment: local, local, scroll, scroll;`,i=`
|
|
3
|
+
.tabs {
|
|
4
|
+
padding-right: 2rem;
|
|
5
|
+
}
|
|
6
|
+
`,l=document.createElement("style");l.innerText=i,c.forEach(e=>{const n=e.clientWidth;let a=e.querySelector(".tabs");if(a||(a=e.querySelector('[data-real-class*="tabs"]')),a.scrollWidth>n&&!a.innerHTML.includes("icon is-small is-absolute")){const d=`<span class="icon is-small is-absolute" style="${t}"><i class="tri-arrow-right" aria-hidden='true'></i></span>`;a.innerHTML+=d,a.appendChild(l)}});let s=document.querySelectorAll("[data-tabs-context]");for(let e=0;e<s.length;e++){let n=s[e],a=n.querySelectorAll("[data-tab-navigation]"),u=n.querySelectorAll("[data-tab-content]");for(let o=0;o<a.length;o++){let f=a[o],m=u[o];f.addEventListener("click",function(){r(f,m)}),f.addEventListener("keyup",p=>{switch(p.preventDefault(),p.keyCode){case 35:r(a[a.length-1],u[a.length-1]);break;case 36:r(a[0],u[0]);break;case 37:let h=(o-1)%a.length;r(a[h],u[h]);break;case 39:let v=(o+1)%a.length;r(a[v],u[v]);break}})}const d=()=>{for(let o=0;o<a.length;o++)a[o].classList.remove("is-active"),a[o].setAttribute("aria-selected","false"),a[o].setAttribute("tabindex","-1");for(let o=0;o<u.length;o++)u[o].classList.remove("is-active"),u[o].setAttribute("aria-expanded","false")},r=(o,f)=>{d(),o.classList.add("is-active"),o.setAttribute("aria-selected","true"),o.setAttribute("tabindex","0"),o.focus(),f.classList.add("is-active"),f.setAttribute("aria-expanded","true")};n.setAttribute("data-tab-initialized","true")}},O=()=>{document.querySelectorAll("[data-autocomplete-context]").forEach(t=>{const i=t.querySelector("[data-autocomplete-input]"),l=t.querySelector("[data-autocomplete-menu]"),s=l.querySelectorAll(".autocomplete-item");let e=-1,n="";const a=()=>{e=-1,document.body.classList.remove("autocomplete-close"),t.classList.remove("is-active"),i.blur(),s.forEach(d=>{d.removeAttribute("data-autocomplete-item-hover")})};l.querySelectorAll(".autocomplete-item").forEach((d,r)=>{d.setAttribute("data-autocomplete-item-index",String(r))}),i.addEventListener("focus",d=>{d.stopPropagation(),t.closest(".is-autocomplete").classList.add("is-active"),document.body.classList.add("autocomplete-close");const r=[];s.forEach(o=>{o.textContent.trim().toLocaleLowerCase().includes(i.value.trim().toLocaleLowerCase())?(o.style.display="block",r.push(o)):o.style.display="none",o.removeAttribute("data-autocomplete-item-index")}),r.forEach((o,f)=>{o.setAttribute("data-autocomplete-item-index",String(f))})}),s.forEach(d=>{d.addEventListener("mousemove",()=>{s.forEach(o=>{o.removeAttribute("data-autocomplete-item-hover")});const r=d.getAttribute("data-autocomplete-item-index");e=Number(r),d.setAttribute("data-autocomplete-item-hover","true"),n=""}),d.addEventListener("mouseout",()=>{d.removeAttribute("data-autocomplete-item-hover")}),d.addEventListener("click",r=>{const o=r.target;i.value=o.textContent,a()})}),i.addEventListener("input",d=>{const r=d.target;e!==-1&&(e=-1);const o=[];s.forEach(f=>{f.textContent.trim().toLocaleLowerCase().includes(r.value.trim().toLocaleLowerCase())?(f.style.display="block",o.push(f)):f.style.display="none",f.removeAttribute("data-autocomplete-item-index"),f.removeAttribute("data-autocomplete-item-hover")}),o.forEach((f,m)=>{f.setAttribute("data-autocomplete-item-index",String(m))})}),i.addEventListener("keydown",d=>{const r=l.querySelectorAll("[data-autocomplete-item-index]");d.key==="ArrowDown"&&(e=e+1,e===r.length&&(e=0)),d.key==="ArrowUp"&&(e=e-1,e<0&&(e=r.length-1)),["ArrowDown","ArrowUp"].includes(d.key)&&(r.forEach(o=>{o.removeAttribute("data-autocomplete-item-hover")}),r[e].setAttribute("data-autocomplete-item-hover","true"),n=r[e].textContent),d.key==="Enter"&&n.trim().length>0&&(i.value=n,a())}),i.addEventListener("blur",()=>{setTimeout(()=>a(),100)}),t.setAttribute("data-autocomplete-initialized","true")})},M=()=>{document.querySelectorAll(".segmented-control-item").forEach(t=>{t.addEventListener("click",function(){this.parentElement.querySelector(".is-active").classList.remove("is-active"),t.classList.contains("is-active")||t.classList.add("is-active")}),t.setAttribute("data-segmentedControl-initialized","true")})},$=()=>{document.querySelectorAll(".textarea-wrapper").forEach(t=>{if(!t.getAttribute("data-textarea-initialized")){const s=t.querySelector("textarea.textarea"),e=s.getAttribute("maxlength");if(e){var l=0;const n=document.createElement("div");n.classList.add("counter"),n.innerHTML=`${l}/${e}`,t.appendChild(n),s.addEventListener("input",function(a){l=this.value.length,n.innerHTML=`${l}/${e}`,l===10&&a.preventDefault()})}t.setAttribute("data-textarea-initialized","true")}})},F=c=>{c.forEach(t=>{t.classList.remove("is-active")})},T=()=>{document.querySelectorAll(".chips-list").forEach(t=>{if(!t.getAttribute("data-chips-initialized")){const l=t.querySelectorAll(".chips"),s=t.classList.contains("is-multiple");l.forEach(e=>{e.classList.contains("is-disabled")||e.addEventListener("click",function(){s||F(l),e.classList.toggle("is-active")})}),t.setAttribute("data-chips-initialized","true")}})},R=c=>{if(!c.getAttribute("data-progress-radial-initialized")){let i=Number(c.getAttribute("data-progress-radial-first-value")),l=Number(c.getAttribute("data-progress-radial-second-value")),s="",e=0,n=0;if(l===0){const a=setInterval(()=>{e!==i?e+=1:clearInterval(a),s=`radial-gradient(white 58%, transparent 51%),
|
|
7
|
+
conic-gradient(#0C7B91 0deg ${360*(e/100)}deg,
|
|
8
|
+
gainsboro ${360*(e/100)}deg 360deg)`,c.style.background=s},13)}else{l+=i;const a=setInterval(()=>{e<i&&(e+=1),n<l?n+=1:clearInterval(a),s=`radial-gradient(white 58%, transparent 51%),
|
|
9
|
+
conic-gradient(#0C7B91 0deg ${360*(e/100)}deg,
|
|
10
|
+
#25465f ${360*(e/100)}deg ${360*(n/100)}deg,
|
|
11
|
+
gainsboro ${360*(n/100)}deg 360deg)`,c.style.background=s},13)}c.setAttribute("data-progress-radial-initialized","true")}},_=c=>{let t=c.querySelector(".range-cursor-min"),i=c.querySelector(".range-cursor-max"),l=c.querySelector(".range-track"),s=c.querySelector(".range-value-min"),e=c.querySelector(".range-value-max"),n=t.max,a=0;const u=()=>{let d=Number(t.value)/Number(n)*100,r=Number(i.value)/Number(n)*100;l.style.background=`linear-gradient(to right, #E1E1E1 ${d}% , #0C7B91 ${d}% , #0C7B91 ${r}%, #E1E1E1 ${r}%) `};u(),t.addEventListener("input",d=>{const r=d.target;Number(r.value)<Number(i.value)-a?t.value=r.value:t.value=String(Number(i.value)-a),s.textContent=r.value,u()}),i.addEventListener("input",d=>{const r=d.target;Number(r.value)>Number(t.value)+a?i.value=r.value:i.value=String(Number(t.value)+a),e.textContent=r.value,u()}),c.setAttribute("data-ranges-initialized","true")},G=(c,t)=>{new IntersectionObserver(l=>{l.forEach(s=>{s.isIntersecting&&t(s.target)})}).observe(c)},V=()=>{const c=document.querySelectorAll("[data-select-name]");c&&c.forEach(t=>{const i=t.querySelector("label");if(!t.classList.contains("select-disabled")){const l=t.parentNode;let s=l.querySelector("[data-is-open-options]");t.addEventListener("click",()=>{const n=s.getAttribute("data-is-open-options");n==="true"&&s.setAttribute("data-is-open-options","false"),n==="false"&&s.setAttribute("data-is-open-options","true")}),t.addEventListener("blur",()=>{s.setAttribute("data-is-open-options","false")});const e=s.querySelectorAll("[data-option-name]");e.forEach(n=>{n.classList.contains("select-options-option-disabled")||n.addEventListener("mousedown",()=>{e.forEach(u=>u.classList.remove("select-options-option-activated")),n.classList.add("select-options-option-activated");let a=t.querySelector("[data-option-selected]");a||(a=document.createElement("span"),a.classList.add("select-value"),(!i||i===null)&&a.classList.add("no-label"),t.appendChild(a)),t.setAttribute("data-option-selected",n.getAttribute("data-option-name")),a.setAttribute("data-option-selected",n.getAttribute("data-option-name")),a.textContent=n.getAttribute("data-option-name"),l.classList.add("has-dynamic-placeholder")})})}t.setAttribute("data-selects-initialized","true")})},B=()=>{const c=document.querySelectorAll("[data-has-gauge]");c&&c.forEach(t=>{var S,x;const i="#007B52",l="#707070",s="#D42D02",e="#FFBB33",n=t.querySelector("input"),a=t.querySelector("[data-gauge]"),u=(S=t.querySelector("[data-length-min]"))==null?void 0:S.getAttribute("data-length-min"),d=(x=t.querySelector("[data-length-max]"))==null?void 0:x.getAttribute("data-length-max"),r={},o={fn:g=>d&&!u?g.length>0&&g.length<=Number(d):u&&!d?g.length>=Number(u):d&&u?g.length>=Number(u)&&g.length<=Number(d):!1,ref:t.querySelector("[data-security-length]")},f={fn:g=>/[^\w\*]/.test(g),ref:t.querySelector("[data-security-special-chars]")},m={fn:g=>/[0-9]/.test(g),ref:t.querySelector("[data-security-number]")},p={fn:g=>/[A-Z]/.test(g),ref:t.querySelector("[data-security-uppercase]")},h={fn:g=>/[a-z]/.test(g),ref:t.querySelector("[data-security-lowercase]")};m.ref&&Object.assign(r,{numberVerify:m}),o.ref&&Object.assign(r,{lengthVerify:o}),h.ref&&Object.assign(r,{lowercaseVerify:h}),p.ref&&Object.assign(r,{uppercaseVerify:p}),f.ref&&Object.assign(r,{specialCharsverify:f}),Object.keys(r).length;const v=g=>{const b=[];return Object.keys(r).map(y=>{const C=r[y].fn(g),L=r[y].ref.querySelector("[data-icon-securities]").querySelector("i");b.push(C),C?(L.classList.remove("tri-times-circle"),L.classList.add("tri-check-circle","is-success")):(L.classList.remove("tri-check-circle","is-success"),L.classList.add("tri-times-circle"))}),b.filter(y=>y).length},q=g=>{const b=Number((g/Object.keys(r).length*100).toFixed(0));b<=50&&b>0?(a.style.width="50%",a.style.backgroundColor=s):b<=99&&b>50?(a.style.width="75%",a.style.backgroundColor=e):b===100?(a.style.width="100%",a.style.backgroundColor=i):(a.style.width="0%",a.style.backgroundColor=l)},w=g=>{const b=g.target.value,y=v(b);q(y)};n.addEventListener("input",w),t.setAttribute("data-gauges-initialized","true")})},j=()=>{const c=document.querySelectorAll("[data-show-pwd]");c&&c.forEach(t=>{const i=e=>{e.classList.contains("tri-eye")?(e.classList.remove("tri-eye"),e.classList.add("tri-eye-slash")):(e.classList.remove("tri-eye-slash"),e.classList.add("tri-eye"))},l=e=>{const n=e.parentNode.parentNode;let a=n.querySelector("input");a||(a=n.parentNode.querySelector("input")),a.type==="password"?a.type="text":a.type="password"},s=e=>{const n=e.target;i(n),l(n)};t.addEventListener("click",s),t.setAttribute("data-iconsShowPwd-initialized","true")})},D=()=>{N(),A(),E(),k(),I(),z(),O(),M(),$(),T(),V(),B(),j()};let P=!1;P||document.addEventListener("DOMContentLoaded",function(){D(),P=!0;const c={attributes:!0,childList:!0,subtree:!0};new MutationObserver(function(i){i.forEach(function(l){const s=l.target;if(s){const e=s.querySelectorAll("[data-modal-context]"),n=s.querySelectorAll(".accordions"),a=s.querySelectorAll(".countdown"),u=s.querySelectorAll("[data-tabs-context]"),d=s.querySelectorAll("[data-autocomplete-context]"),r=s.querySelectorAll('[data-variant="auto"]'),o=s.querySelectorAll(".segmented-control-item"),f=document.querySelectorAll(".textarea"),m=document.querySelectorAll(".progress-radial"),p=document.querySelectorAll(".range-container"),h=document.querySelectorAll(".chips-list"),v=s.querySelectorAll("[data-select-name]"),q=document.querySelectorAll("[data-has-gauge]"),w=document.querySelectorAll("[data-show-pwd]"),S=s.querySelectorAll("[data-expandable-row]");[{modal:e},{accordion:n},{tab:u},{countdown:a},{autocomplete:d},{fontVariant:r},{segmentedControl:o},{textareas:f},{ranges:p},{progressRadials:m},{chips:h},{selects:v},{gauges:q},{iconsShowPwd:w},{tableexpansion:S}].forEach(g=>{const b=Object.keys(g)[0];g[b].length&&g[b].forEach(y=>{if(y.getAttribute(`data-${b}-initialized`)!=="true")switch(y.setAttribute(`data-${b}-initialized`,"true"),b){case"modal":return A();case"tab":return N();case"accordion":return z();case"countdown":return k();case"autocomplete":return O();case"fontVariant":return E();case"segmentedControl":return M();case"textareas":return $();case"chips":return T();case"selects":return V();case"ranges":return _(y);case"progressRadials":return G(y,R);case"gauges":return B();case"iconsShowPwd":return j();case"tableexpansion":return I();default:return D()}})})}})}).observe(document.documentElement,c)})});
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@trilogy-ds/vanilla",
|
|
3
|
+
"version": "0.0.1-beta.9",
|
|
4
|
+
"author": "Bouygues Telecom",
|
|
5
|
+
"main": "lib/trilogy-ds-vanilla.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "webpack --watch",
|
|
8
|
+
"build": "vite --config vite.config.js build"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git"
|
|
12
|
+
},
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"eslint": "4.19.1",
|
|
16
|
+
"typescript": "^4.1.5",
|
|
17
|
+
"rimraf": "^3.0.2",
|
|
18
|
+
"ts-loader": "^8.0.17",
|
|
19
|
+
"fork-ts-checker-webpack-plugin": "^6.1.0",
|
|
20
|
+
"vite": "^4.5.2",
|
|
21
|
+
"vite-tsconfig-paths": "^4.3.1"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/app.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { initModals } from './components/modal'
|
|
2
|
+
import { initVariant } from './components/font-variant'
|
|
3
|
+
import { initCountdowns } from './components/countdown'
|
|
4
|
+
import { initAccordions } from './components/accordion'
|
|
5
|
+
import { initTableExpansion } from './components/table-expansion'
|
|
6
|
+
import { initTabs } from './components/tabs'
|
|
7
|
+
import { initAutocomplete } from './components/autocomplete'
|
|
8
|
+
import { initSegmentedControl } from './components/segmented-control'
|
|
9
|
+
import { initTextarea } from './components/textarea'
|
|
10
|
+
import { initChips } from './components/chips'
|
|
11
|
+
import { initProgressRadial } from './components/progress-radial'
|
|
12
|
+
import { initRange } from './components/range'
|
|
13
|
+
import { intersectionObserver } from './utils/intersectionObserver'
|
|
14
|
+
import { initSelects } from './components/select'
|
|
15
|
+
import { initInputGauge } from './components/input-gauge'
|
|
16
|
+
import { initInputIcon } from './components/input-icon'
|
|
17
|
+
|
|
18
|
+
const loadVanilla = () => {
|
|
19
|
+
initTabs()
|
|
20
|
+
initModals()
|
|
21
|
+
initVariant()
|
|
22
|
+
initCountdowns()
|
|
23
|
+
initTableExpansion()
|
|
24
|
+
initAccordions()
|
|
25
|
+
initAutocomplete()
|
|
26
|
+
initSegmentedControl()
|
|
27
|
+
initTextarea()
|
|
28
|
+
initChips()
|
|
29
|
+
initSelects()
|
|
30
|
+
initInputGauge()
|
|
31
|
+
initInputIcon()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let isInitialized = false
|
|
35
|
+
|
|
36
|
+
if (!isInitialized) {
|
|
37
|
+
// when DOM is loaded
|
|
38
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
39
|
+
loadVanilla()
|
|
40
|
+
|
|
41
|
+
// Assign variable to true
|
|
42
|
+
isInitialized = true
|
|
43
|
+
|
|
44
|
+
// Observer config
|
|
45
|
+
const observerConfig = {
|
|
46
|
+
attributes: true,
|
|
47
|
+
childList: true,
|
|
48
|
+
subtree: true,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Checking mutations
|
|
52
|
+
const mutationObserver = new MutationObserver(function (mutations: MutationRecord[]) {
|
|
53
|
+
mutations.forEach(function (mutation: MutationRecord) {
|
|
54
|
+
const mutationTarget = mutation.target as HTMLElement
|
|
55
|
+
|
|
56
|
+
if (mutationTarget) {
|
|
57
|
+
const modals = mutationTarget.querySelectorAll('[data-modal-context]')
|
|
58
|
+
const accordions = mutationTarget.querySelectorAll('.accordions')
|
|
59
|
+
const countdowns = mutationTarget.querySelectorAll('.countdown')
|
|
60
|
+
const tabs = mutationTarget.querySelectorAll('[data-tabs-context]')
|
|
61
|
+
const autocomplete = mutationTarget.querySelectorAll('[data-autocomplete-context]')
|
|
62
|
+
const fontVariant = mutationTarget.querySelectorAll('[data-variant="auto"]')
|
|
63
|
+
const segmentedControl = mutationTarget.querySelectorAll('.segmented-control-item')
|
|
64
|
+
const textareas = document.querySelectorAll('.textarea')
|
|
65
|
+
const progressRadials = document.querySelectorAll('.progress-radial')
|
|
66
|
+
const ranges = document.querySelectorAll('.range-container')
|
|
67
|
+
const chips = document.querySelectorAll('.chips-list')
|
|
68
|
+
const selects = mutationTarget.querySelectorAll('[data-select-name]')
|
|
69
|
+
const gauges = document.querySelectorAll<HTMLElement>('[data-has-gauge]')
|
|
70
|
+
const iconsShowPwd = document.querySelectorAll<HTMLElement>('[data-show-pwd]')
|
|
71
|
+
const tableexpansion = mutationTarget.querySelectorAll('[data-expandable-row]')
|
|
72
|
+
|
|
73
|
+
const elements = [
|
|
74
|
+
{ modal: modals },
|
|
75
|
+
{ accordion: accordions },
|
|
76
|
+
{ tab: tabs },
|
|
77
|
+
{ countdown: countdowns },
|
|
78
|
+
{ autocomplete: autocomplete },
|
|
79
|
+
{ fontVariant: fontVariant },
|
|
80
|
+
{ segmentedControl: segmentedControl },
|
|
81
|
+
{ textareas: textareas },
|
|
82
|
+
{ ranges: ranges },
|
|
83
|
+
{ progressRadials: progressRadials },
|
|
84
|
+
{ chips: chips },
|
|
85
|
+
{ selects: selects },
|
|
86
|
+
{ gauges: gauges },
|
|
87
|
+
{ iconsShowPwd: iconsShowPwd },
|
|
88
|
+
{ tableexpansion: tableexpansion },
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
elements.forEach((element: any) => {
|
|
92
|
+
const key = Object.keys(element)[0]
|
|
93
|
+
if (element[key].length) {
|
|
94
|
+
element[key].forEach((htmlElement: HTMLElement) => {
|
|
95
|
+
const initialized = htmlElement.getAttribute(`data-${key}-initialized`)
|
|
96
|
+
if (initialized !== 'true') {
|
|
97
|
+
htmlElement.setAttribute(`data-${key}-initialized`, 'true')
|
|
98
|
+
switch (key) {
|
|
99
|
+
case 'modal':
|
|
100
|
+
return initModals()
|
|
101
|
+
case 'tab':
|
|
102
|
+
return initTabs()
|
|
103
|
+
case 'accordion':
|
|
104
|
+
return initAccordions()
|
|
105
|
+
case 'countdown':
|
|
106
|
+
return initCountdowns()
|
|
107
|
+
case 'autocomplete':
|
|
108
|
+
return initAutocomplete()
|
|
109
|
+
case 'fontVariant':
|
|
110
|
+
return initVariant()
|
|
111
|
+
case 'segmentedControl':
|
|
112
|
+
return initSegmentedControl()
|
|
113
|
+
case 'textareas':
|
|
114
|
+
return initTextarea()
|
|
115
|
+
case 'chips':
|
|
116
|
+
return initChips()
|
|
117
|
+
case 'selects':
|
|
118
|
+
return initSelects()
|
|
119
|
+
case 'ranges':
|
|
120
|
+
return initRange(htmlElement)
|
|
121
|
+
case 'progressRadials':
|
|
122
|
+
return intersectionObserver(htmlElement, initProgressRadial)
|
|
123
|
+
case 'gauges':
|
|
124
|
+
return initInputGauge()
|
|
125
|
+
case 'iconsShowPwd':
|
|
126
|
+
return initInputIcon()
|
|
127
|
+
case 'tableexpansion':
|
|
128
|
+
return initTableExpansion()
|
|
129
|
+
default:
|
|
130
|
+
return loadVanilla()
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
mutationObserver.observe(document.documentElement, observerConfig)
|
|
141
|
+
})
|
|
142
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const _closeAccordionContexts = (accordionsContexts: NodeListOf<HTMLElement>) => {
|
|
2
|
+
if (accordionsContexts.length) {
|
|
3
|
+
accordionsContexts.forEach((accordionContext: HTMLElement) => {
|
|
4
|
+
const accordionButton = accordionContext.querySelector('button.toggle')
|
|
5
|
+
accordionContext.classList.remove('is-active')
|
|
6
|
+
accordionButton.setAttribute('aria-expanded', 'false')
|
|
7
|
+
})
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const _loadAccordion = (accordion: HTMLElement) => {
|
|
12
|
+
const accordionsContexts: NodeListOf<HTMLElement> = accordion.querySelectorAll('[data-accordion-context]')
|
|
13
|
+
accordionsContexts.forEach((context) => {
|
|
14
|
+
const toggle = context.querySelector('[data-accordion-toggle]')
|
|
15
|
+
const accordionButton = context.querySelector('button.toggle')
|
|
16
|
+
toggle.addEventListener('click', () => {
|
|
17
|
+
if (!context.classList.contains('is-disabled')) {
|
|
18
|
+
if (context.classList.contains('is-active')) {
|
|
19
|
+
context.classList.remove('is-active')
|
|
20
|
+
accordionButton.setAttribute('aria-expanded', 'false')
|
|
21
|
+
} else {
|
|
22
|
+
_closeAccordionContexts(accordionsContexts)
|
|
23
|
+
context.classList.toggle('is-active')
|
|
24
|
+
accordionButton.setAttribute('aria-expanded', 'true')
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
accordion.setAttribute('data-accordion-initialized', 'true')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const initAccordions = () => {
|
|
33
|
+
const allAccordions = document.querySelectorAll('[data-accordion], .accordions')
|
|
34
|
+
allAccordions.forEach((accordion: HTMLElement) => {
|
|
35
|
+
_loadAccordion(accordion)
|
|
36
|
+
})
|
|
37
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
export const initAutocomplete = () => {
|
|
2
|
+
const autocompleteContainer = document.querySelectorAll('[data-autocomplete-context]')
|
|
3
|
+
|
|
4
|
+
autocompleteContainer.forEach((autocompleteConainterElmt: HTMLDivElement) => {
|
|
5
|
+
const inputAutocomplete: HTMLInputElement = autocompleteConainterElmt.querySelector('[data-autocomplete-input]')
|
|
6
|
+
const autocompleteMenu: HTMLDivElement = autocompleteConainterElmt.querySelector('[data-autocomplete-menu]')
|
|
7
|
+
const autocompleteItems = autocompleteMenu.querySelectorAll('.autocomplete-item')
|
|
8
|
+
|
|
9
|
+
let currentItems = -1
|
|
10
|
+
let itemSelected = ''
|
|
11
|
+
|
|
12
|
+
const onBlur = () => {
|
|
13
|
+
currentItems = -1
|
|
14
|
+
document.body.classList.remove('autocomplete-close')
|
|
15
|
+
autocompleteConainterElmt.classList.remove('is-active')
|
|
16
|
+
inputAutocomplete.blur()
|
|
17
|
+
autocompleteItems.forEach((item: HTMLDivElement) => {
|
|
18
|
+
item.removeAttribute('data-autocomplete-item-hover')
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// add data attributte on items
|
|
23
|
+
const itemsList = autocompleteMenu.querySelectorAll('.autocomplete-item')
|
|
24
|
+
itemsList.forEach((item: HTMLDivElement, index: number) => {
|
|
25
|
+
item.setAttribute('data-autocomplete-item-index', String(index))
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// Open suggestions
|
|
29
|
+
inputAutocomplete.addEventListener('focus', (eventFocus: FocusEvent) => {
|
|
30
|
+
eventFocus.stopPropagation()
|
|
31
|
+
autocompleteConainterElmt.closest('.is-autocomplete').classList.add('is-active')
|
|
32
|
+
document.body.classList.add('autocomplete-close')
|
|
33
|
+
const items: HTMLDivElement[] = []
|
|
34
|
+
|
|
35
|
+
// open with suggestions filtered
|
|
36
|
+
autocompleteItems.forEach((item: HTMLDivElement) => {
|
|
37
|
+
if (item.textContent.trim().toLocaleLowerCase().includes(inputAutocomplete.value.trim().toLocaleLowerCase())) {
|
|
38
|
+
item.style.display = 'block'
|
|
39
|
+
items.push(item)
|
|
40
|
+
} else {
|
|
41
|
+
item.style.display = 'none'
|
|
42
|
+
}
|
|
43
|
+
item.removeAttribute('data-autocomplete-item-index')
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
items.forEach((item: HTMLDivElement, index: number) => {
|
|
47
|
+
item.setAttribute('data-autocomplete-item-index', String(index))
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
// on hover and blur item
|
|
52
|
+
autocompleteItems.forEach((autocompleteItem: HTMLDivElement) => {
|
|
53
|
+
autocompleteItem.addEventListener('mousemove', () => {
|
|
54
|
+
autocompleteItems.forEach((i: HTMLDivElement) => {
|
|
55
|
+
i.removeAttribute('data-autocomplete-item-hover')
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const index = autocompleteItem.getAttribute('data-autocomplete-item-index')
|
|
59
|
+
currentItems = Number(index)
|
|
60
|
+
autocompleteItem.setAttribute('data-autocomplete-item-hover', 'true')
|
|
61
|
+
itemSelected = ''
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
autocompleteItem.addEventListener('mouseout', () => {
|
|
65
|
+
autocompleteItem.removeAttribute('data-autocomplete-item-hover')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
autocompleteItem.addEventListener('click', (eventClick: MouseEvent) => {
|
|
69
|
+
const targetItem = eventClick.target as HTMLInputElement
|
|
70
|
+
inputAutocomplete.value = targetItem.textContent
|
|
71
|
+
onBlur()
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// filter suggestions
|
|
76
|
+
inputAutocomplete.addEventListener('input', (eventInput: InputEvent) => {
|
|
77
|
+
const target = eventInput.target as HTMLInputElement
|
|
78
|
+
if (currentItems !== -1) currentItems = -1
|
|
79
|
+
const items: HTMLDivElement[] = []
|
|
80
|
+
|
|
81
|
+
autocompleteItems.forEach((item: HTMLDivElement) => {
|
|
82
|
+
if (item.textContent.trim().toLocaleLowerCase().includes(target.value.trim().toLocaleLowerCase())) {
|
|
83
|
+
item.style.display = 'block'
|
|
84
|
+
items.push(item)
|
|
85
|
+
} else {
|
|
86
|
+
item.style.display = 'none'
|
|
87
|
+
}
|
|
88
|
+
item.removeAttribute('data-autocomplete-item-index')
|
|
89
|
+
item.removeAttribute('data-autocomplete-item-hover')
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
items.forEach((item: HTMLDivElement, index: number) => {
|
|
93
|
+
item.setAttribute('data-autocomplete-item-index', String(index))
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
// on select items with keyboard
|
|
98
|
+
inputAutocomplete.addEventListener('keydown', (eventKeyboard: KeyboardEvent) => {
|
|
99
|
+
const itemsList = autocompleteMenu.querySelectorAll('[data-autocomplete-item-index]')
|
|
100
|
+
|
|
101
|
+
if (eventKeyboard.key === 'ArrowDown') {
|
|
102
|
+
currentItems = currentItems + 1
|
|
103
|
+
if (currentItems === itemsList.length) currentItems = 0
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (eventKeyboard.key === 'ArrowUp') {
|
|
107
|
+
currentItems = currentItems - 1
|
|
108
|
+
if (currentItems < 0) currentItems = itemsList.length - 1
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (['ArrowDown', 'ArrowUp'].includes(eventKeyboard.key)) {
|
|
112
|
+
itemsList.forEach((item: HTMLDivElement) => {
|
|
113
|
+
item.removeAttribute('data-autocomplete-item-hover')
|
|
114
|
+
})
|
|
115
|
+
itemsList[currentItems].setAttribute('data-autocomplete-item-hover', 'true')
|
|
116
|
+
itemSelected = itemsList[currentItems].textContent
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (eventKeyboard.key === 'Enter' && itemSelected.trim().length > 0) {
|
|
120
|
+
inputAutocomplete.value = itemSelected
|
|
121
|
+
onBlur()
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
// on blur
|
|
126
|
+
// set timeout for click item before blur input
|
|
127
|
+
inputAutocomplete.addEventListener('blur', () => {
|
|
128
|
+
setTimeout(() => onBlur(), 100)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
autocompleteConainterElmt.setAttribute(`data-autocomplete-initialized`, 'true')
|
|
132
|
+
})
|
|
133
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const _resetChips = (chipsList: any) => {
|
|
2
|
+
chipsList.forEach((chips: any) => {
|
|
3
|
+
chips.classList.remove('is-active');
|
|
4
|
+
})
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const initChips = () => {
|
|
8
|
+
const allChipsLists = document.querySelectorAll(".chips-list");
|
|
9
|
+
|
|
10
|
+
allChipsLists.forEach((chipsList: any) => {
|
|
11
|
+
const isInitialized = chipsList.getAttribute('data-chips-initialized');
|
|
12
|
+
if (!isInitialized) {
|
|
13
|
+
const chips = chipsList.querySelectorAll('.chips');
|
|
14
|
+
const isMultiple = chipsList.classList.contains('is-multiple');
|
|
15
|
+
chips.forEach((chip: HTMLElement) => {
|
|
16
|
+
if (!chip.classList.contains('is-disabled')) {
|
|
17
|
+
chip.addEventListener("click", function () {
|
|
18
|
+
if (!isMultiple) {
|
|
19
|
+
_resetChips(chips);
|
|
20
|
+
}
|
|
21
|
+
chip.classList.toggle('is-active');
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
chipsList.setAttribute('data-chips-initialized', 'true');
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const initCountdowns = () => {
|
|
2
|
+
|
|
3
|
+
let countdowns: NodeListOf<HTMLElement> = document.querySelectorAll('[data-countdown]');
|
|
4
|
+
|
|
5
|
+
countdowns.forEach((countdown: HTMLElement) => {
|
|
6
|
+
const second = 1000,
|
|
7
|
+
minute = second * 60,
|
|
8
|
+
hour = minute * 60,
|
|
9
|
+
day = hour * 24;
|
|
10
|
+
|
|
11
|
+
let countdownElements = countdown;
|
|
12
|
+
let countDown = new Date(countdownElements.dataset.date).getTime();
|
|
13
|
+
let numbersDays: HTMLElement = countdownElements.querySelector('[data-days]');
|
|
14
|
+
let numbersHours: HTMLElement = countdownElements.querySelector('[data-hours]');
|
|
15
|
+
let numbersMinutes: HTMLElement = countdownElements.querySelector('[data-minutes]');
|
|
16
|
+
let numbersSeconds: HTMLElement = countdownElements.querySelector('[data-seconds]');
|
|
17
|
+
|
|
18
|
+
let timer = setInterval(() => {
|
|
19
|
+
|
|
20
|
+
let now = new Date().getTime();
|
|
21
|
+
let distance = 0;
|
|
22
|
+
if ((countDown - now) > 0) {
|
|
23
|
+
distance = (countDown - now);
|
|
24
|
+
}
|
|
25
|
+
if (distance <= 0) {
|
|
26
|
+
clearInterval(timer);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
numbersDays.innerText = Math.floor(distance / (day)).toString(),
|
|
30
|
+
numbersHours.innerText = Math.floor((distance % (day)) / (hour)).toString(),
|
|
31
|
+
numbersMinutes.innerText = Math.floor((distance % (hour)) / (minute)).toString(),
|
|
32
|
+
numbersSeconds.innerText = Math.floor((distance % (minute)) / second).toString();
|
|
33
|
+
|
|
34
|
+
}, second)
|
|
35
|
+
countdownElements.setAttribute(`data-countdown-initialized`, 'true')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default initCountdowns;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export const initVariant = () => {
|
|
2
|
+
let titres = document.querySelectorAll('[data-variant="auto"]');
|
|
3
|
+
|
|
4
|
+
const hashCode = function (string: string) {
|
|
5
|
+
let hashNumbers = 0;
|
|
6
|
+
let hashLength = string.length;
|
|
7
|
+
let i = 0;
|
|
8
|
+
|
|
9
|
+
if (hashLength > 0) {
|
|
10
|
+
while (i < hashLength) {
|
|
11
|
+
hashNumbers = (hashNumbers << 5) - hashNumbers + string.charCodeAt(i++) | 0;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return hashNumbers;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
for (let i = 0; i < titres.length; i++) {
|
|
18
|
+
let titre = titres[i];
|
|
19
|
+
const content = titre.textContent;
|
|
20
|
+
const charsArray = ['b', 'g', 'o', 'q'];
|
|
21
|
+
const charsIndexes: number[] = [];
|
|
22
|
+
|
|
23
|
+
content.toLowerCase().split('').map((i, j) => {
|
|
24
|
+
if (charsArray.indexOf(i) > -1) {
|
|
25
|
+
charsIndexes.push(j);
|
|
26
|
+
}
|
|
27
|
+
return i;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (charsIndexes.length) {
|
|
31
|
+
const hashContent = hashCode(content);
|
|
32
|
+
const position = Math.abs(hashContent % charsIndexes.length);
|
|
33
|
+
const char = content.charAt(charsIndexes[position]);
|
|
34
|
+
const beforeChar = content.substring(0, charsIndexes[position]);
|
|
35
|
+
const afterChar = content.substring(charsIndexes[position] + 1);
|
|
36
|
+
titre.innerHTML = `${beforeChar}<span class="has-variant">${char}</span>${afterChar}`;
|
|
37
|
+
}
|
|
38
|
+
titre.setAttribute(`data-fontVariant-initialized`, 'true')
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default initVariant;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
interface IVerifies {
|
|
2
|
+
[key: string]: { fn: (e: string) => boolean; ref: HTMLElement };
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export const initInputGauge = () => {
|
|
6
|
+
const pwdInput = document.querySelectorAll<HTMLElement>("[data-has-gauge]");
|
|
7
|
+
|
|
8
|
+
if (pwdInput) {
|
|
9
|
+
pwdInput.forEach((htmlElement: HTMLElement) => {
|
|
10
|
+
const green: string = "#007B52";
|
|
11
|
+
const grey: string = "#707070";
|
|
12
|
+
const red: string = "#D42D02";
|
|
13
|
+
const yellow: string = "#FFBB33";
|
|
14
|
+
|
|
15
|
+
const input = htmlElement.querySelector("input") as HTMLElement;
|
|
16
|
+
const gauge = htmlElement.querySelector("[data-gauge]") as HTMLElement;
|
|
17
|
+
const min = htmlElement.querySelector("[data-length-min]")?.getAttribute("data-length-min");
|
|
18
|
+
const max = htmlElement.querySelector("[data-length-max]")?.getAttribute("data-length-max");
|
|
19
|
+
const dataVerifies: IVerifies = {};
|
|
20
|
+
let nbVerified = 0;
|
|
21
|
+
|
|
22
|
+
const lengthVerify = {
|
|
23
|
+
fn: (e: string) => {
|
|
24
|
+
if (max && !min) {
|
|
25
|
+
return e.length > 0 && e.length <= Number(max);
|
|
26
|
+
}
|
|
27
|
+
if (min && !max) {
|
|
28
|
+
return e.length >= Number(min);
|
|
29
|
+
}
|
|
30
|
+
if (max && min) {
|
|
31
|
+
return e.length >= Number(min) && e.length <= Number(max);
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
},
|
|
35
|
+
ref: htmlElement.querySelector("[data-security-length]") as HTMLElement,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const specialCharsverify = {
|
|
39
|
+
fn: (e: string) => /[^\w\*]/.test(e),
|
|
40
|
+
ref: htmlElement.querySelector("[data-security-special-chars]") as HTMLElement,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const numberVerify = {
|
|
44
|
+
fn: (e: string) => /[0-9]/.test(e),
|
|
45
|
+
ref: htmlElement.querySelector("[data-security-number]") as HTMLElement,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const uppercaseVerify = {
|
|
49
|
+
fn: (e: string) => /[A-Z]/.test(e),
|
|
50
|
+
ref: htmlElement.querySelector("[data-security-uppercase]") as HTMLElement,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const lowercaseVerify = {
|
|
54
|
+
fn: (e: string) => /[a-z]/.test(e),
|
|
55
|
+
ref: htmlElement.querySelector("[data-security-lowercase]") as HTMLElement,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
if (numberVerify.ref) Object.assign(dataVerifies, { numberVerify });
|
|
59
|
+
if (lengthVerify.ref) Object.assign(dataVerifies, { lengthVerify });
|
|
60
|
+
if (lowercaseVerify.ref) Object.assign(dataVerifies, { lowercaseVerify });
|
|
61
|
+
if (uppercaseVerify.ref) Object.assign(dataVerifies, { uppercaseVerify });
|
|
62
|
+
if (specialCharsverify.ref) Object.assign(dataVerifies, { specialCharsverify });
|
|
63
|
+
nbVerified = Object.keys(dataVerifies).length;
|
|
64
|
+
|
|
65
|
+
const handleChangeIconsVerify = (e: string): number => {
|
|
66
|
+
const verifiesTests: boolean[] = [];
|
|
67
|
+
|
|
68
|
+
Object.keys(dataVerifies).map((key: string) => {
|
|
69
|
+
const test = dataVerifies[key].fn(e);
|
|
70
|
+
const icon = dataVerifies[key].ref.querySelector("[data-icon-securities]").querySelector("i");
|
|
71
|
+
verifiesTests.push(test);
|
|
72
|
+
|
|
73
|
+
if (test) {
|
|
74
|
+
icon.classList.remove("tri-times-circle");
|
|
75
|
+
icon.classList.add("tri-check-circle", "is-success");
|
|
76
|
+
} else {
|
|
77
|
+
icon.classList.remove("tri-check-circle", "is-success");
|
|
78
|
+
icon.classList.add("tri-times-circle");
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return verifiesTests.filter((item) => item).length;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const handleChangeGauge = (points: number) => {
|
|
85
|
+
const calc = Number(((points / Object.keys(dataVerifies).length) * 100).toFixed(0));
|
|
86
|
+
if (calc <= 50 && calc > 0) {
|
|
87
|
+
gauge.style.width = "50%";
|
|
88
|
+
gauge.style.backgroundColor = red;
|
|
89
|
+
} else if (calc <= 99 && calc > 50) {
|
|
90
|
+
gauge.style.width = "75%";
|
|
91
|
+
gauge.style.backgroundColor = yellow;
|
|
92
|
+
} else if (calc === 100) {
|
|
93
|
+
gauge.style.width = "100%";
|
|
94
|
+
gauge.style.backgroundColor = green;
|
|
95
|
+
} else {
|
|
96
|
+
gauge.style.width = "0%";
|
|
97
|
+
gauge.style.backgroundColor = grey;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const onInput = (e: InputEvent) => {
|
|
102
|
+
const value = (e.target as HTMLInputElement).value;
|
|
103
|
+
const points = handleChangeIconsVerify(value);
|
|
104
|
+
handleChangeGauge(points);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
input.addEventListener("input", onInput);
|
|
108
|
+
htmlElement.setAttribute(`data-gauges-initialized`, 'true')
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const initInputIcon = () => {
|
|
2
|
+
const iconsShowPwd = document.querySelectorAll<HTMLElement>("[data-show-pwd]");
|
|
3
|
+
|
|
4
|
+
if (iconsShowPwd) {
|
|
5
|
+
iconsShowPwd.forEach((htmlElement: HTMLElement) => {
|
|
6
|
+
const changeIcon = (icon: HTMLElement) => {
|
|
7
|
+
if (icon.classList.contains("tri-eye")) {
|
|
8
|
+
icon.classList.remove("tri-eye");
|
|
9
|
+
icon.classList.add("tri-eye-slash");
|
|
10
|
+
} else {
|
|
11
|
+
icon.classList.remove("tri-eye-slash");
|
|
12
|
+
icon.classList.add("tri-eye");
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const changeTypeInput = (icon: HTMLElement) => {
|
|
17
|
+
const parent = icon.parentNode.parentNode;
|
|
18
|
+
let input = parent.querySelector("input");
|
|
19
|
+
if (!input) input = parent.parentNode.querySelector("input");
|
|
20
|
+
if (input.type === "password") {
|
|
21
|
+
input.type = "text";
|
|
22
|
+
} else {
|
|
23
|
+
input.type = "password";
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const handleClickIcon = (e: Event) => {
|
|
28
|
+
const target = e.target as HTMLElement;
|
|
29
|
+
changeIcon(target);
|
|
30
|
+
changeTypeInput(target);
|
|
31
|
+
};
|
|
32
|
+
htmlElement.addEventListener("click", handleClickIcon);
|
|
33
|
+
htmlElement.setAttribute(`data-iconsShowPwd-initialized`, 'true')
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
export const initModals = () => {
|
|
2
|
+
|
|
3
|
+
let modalContexts: NodeListOf<HTMLElement> = document.querySelectorAll('[data-modal-context]');
|
|
4
|
+
|
|
5
|
+
for (let i = 0; i < modalContexts.length; i++) {
|
|
6
|
+
let modalContext: HTMLElement = modalContexts[i];
|
|
7
|
+
|
|
8
|
+
let modalOpenButtons: NodeListOf<HTMLElement> = modalContext.querySelectorAll('[data-modal-open]');
|
|
9
|
+
let modalElement: HTMLElement = modalContext.querySelector('[data-modal]');
|
|
10
|
+
let modalCloseButtons: NodeListOf<HTMLElement> = modalContext.querySelectorAll('[data-modal-close]');
|
|
11
|
+
let modalVideos: NodeListOf<HTMLVideoElement> = modalContext.querySelectorAll('iframe[src*="www.youtube.com"], iframe[src*="player.vimeo.com"], video');
|
|
12
|
+
|
|
13
|
+
for (let j = 0; j < modalOpenButtons.length; j++) {
|
|
14
|
+
let modalOpenButton = modalOpenButtons[j];
|
|
15
|
+
let modalVideo: HTMLVideoElement = modalVideos[j];
|
|
16
|
+
|
|
17
|
+
modalOpenButton.addEventListener('click', function () {
|
|
18
|
+
makeModalActive(modalElement);
|
|
19
|
+
if (!modalVideo) {
|
|
20
|
+
return;
|
|
21
|
+
} else {
|
|
22
|
+
if (modalVideo.tagName.toLowerCase() === 'video') {
|
|
23
|
+
modalVideo.play();
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
modalVideo.src = modalVideo.src + (modalVideo.src.indexOf('?') < 0 ? '?' : '&') + 'autoplay=1';
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
for (let j = 0; j < modalCloseButtons.length; j++) {
|
|
32
|
+
let modalCloseButton = modalCloseButtons[j];
|
|
33
|
+
modalCloseButton.addEventListener('click', function () {
|
|
34
|
+
makeModalInactive(modalElement);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
initClosingListeners(modalElement);
|
|
39
|
+
|
|
40
|
+
// TODO: supprimer en 1.0.0
|
|
41
|
+
// rétrocompatibilité : fermeture de la modal en cliquant n'importe où
|
|
42
|
+
const background: HTMLElement = modalContext.querySelector('.modal-background');
|
|
43
|
+
if (background) {
|
|
44
|
+
background.onclick = function () {
|
|
45
|
+
makeModalInactive(modalElement);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
modalContext.setAttribute(`data-modal-initialized`, 'true')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Initialise l'écoute des événements permettant de fermer une modale
|
|
53
|
+
*/
|
|
54
|
+
function initClosingListeners(modalElement: HTMLElement) {
|
|
55
|
+
document.addEventListener('keyup', function (e: any) {
|
|
56
|
+
e = e || window.event;
|
|
57
|
+
var isEscape = false;
|
|
58
|
+
if ('key' in e) {
|
|
59
|
+
isEscape = (e.key === 'Escape' || e.key === 'Esc');
|
|
60
|
+
} else {
|
|
61
|
+
isEscape = (e.keyCode === 27);
|
|
62
|
+
}
|
|
63
|
+
if (isEscape) {
|
|
64
|
+
makeModalInactive(modalElement);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
document.addEventListener('click', function (e: MouseEvent) {
|
|
69
|
+
const target = e.target as HTMLInputElement
|
|
70
|
+
let modalContent = target.closest('[data-modal-content]');
|
|
71
|
+
let isModal = target.classList.contains('modal');
|
|
72
|
+
if (modalContent === null && isModal == true) {
|
|
73
|
+
makeModalInactive(modalElement);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Make an element active
|
|
80
|
+
* @param { Element } modalElementToMakeActive element to be made active
|
|
81
|
+
*/
|
|
82
|
+
const makeModalActive = (modalElementToMakeActive: HTMLElement) => {
|
|
83
|
+
modalElementToMakeActive.classList.add('is-active');
|
|
84
|
+
document.body.style.overflow = 'hidden';
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Make an element inactive
|
|
89
|
+
* @param { Element } modalElementToMakeInactive element to be made inactive
|
|
90
|
+
*/
|
|
91
|
+
const makeModalInactive = (modalElementToMakeInactive: HTMLElement) => {
|
|
92
|
+
let video: HTMLVideoElement = modalElementToMakeInactive.querySelector('iframe[src*="youtube"], iframe[src*="vimeo"], video');
|
|
93
|
+
if (video) {
|
|
94
|
+
if (video.tagName.toLowerCase() === 'video') {
|
|
95
|
+
video.pause();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
video.src = video.src.replace('&autoplay=1', '').replace('?autoplay=1', '');
|
|
99
|
+
}
|
|
100
|
+
modalElementToMakeInactive.classList.remove('is-active');
|
|
101
|
+
document.body.style.overflow = null;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const initProgressRadial = (progressRadial: HTMLElement) => {
|
|
2
|
+
const isInitialized = progressRadial.getAttribute('data-progress-radial-initialized');
|
|
3
|
+
if (!isInitialized) {
|
|
4
|
+
let firstProgressValueMax: number = Number(progressRadial.getAttribute('data-progress-radial-first-value'));
|
|
5
|
+
let secondProgressValueMax: number = Number(progressRadial.getAttribute('data-progress-radial-second-value'));
|
|
6
|
+
let backgroundStyle: string = '';
|
|
7
|
+
|
|
8
|
+
let firstProgressCurrentValue: number = 0;
|
|
9
|
+
let secondProgressCurrentValue: number = 0;
|
|
10
|
+
|
|
11
|
+
// If second value does not exist
|
|
12
|
+
if (secondProgressValueMax === 0) {
|
|
13
|
+
const animation = setInterval(() => {
|
|
14
|
+
if (firstProgressCurrentValue !== firstProgressValueMax) {
|
|
15
|
+
firstProgressCurrentValue += 1;
|
|
16
|
+
} else {
|
|
17
|
+
clearInterval(animation);
|
|
18
|
+
}
|
|
19
|
+
backgroundStyle = `radial-gradient(white 58%, transparent 51%),
|
|
20
|
+
conic-gradient(#0C7B91 0deg ${(360 * (firstProgressCurrentValue / 100))}deg,
|
|
21
|
+
gainsboro ${(360 * (firstProgressCurrentValue / 100))}deg 360deg)`;
|
|
22
|
+
progressRadial.style.background = backgroundStyle;
|
|
23
|
+
}, 13);
|
|
24
|
+
} else {
|
|
25
|
+
secondProgressValueMax += firstProgressValueMax;
|
|
26
|
+
const animation = setInterval(() => {
|
|
27
|
+
if (firstProgressCurrentValue < firstProgressValueMax) {
|
|
28
|
+
firstProgressCurrentValue += 1;
|
|
29
|
+
}
|
|
30
|
+
if (secondProgressCurrentValue < secondProgressValueMax) {
|
|
31
|
+
secondProgressCurrentValue += 1;
|
|
32
|
+
} else {
|
|
33
|
+
clearInterval(animation);
|
|
34
|
+
}
|
|
35
|
+
backgroundStyle = `radial-gradient(white 58%, transparent 51%),
|
|
36
|
+
conic-gradient(#0C7B91 0deg ${(360 * (firstProgressCurrentValue / 100))}deg,
|
|
37
|
+
#25465f ${(360 * (firstProgressCurrentValue / 100))}deg ${(360 * (secondProgressCurrentValue / 100))}deg,
|
|
38
|
+
gainsboro ${(360 * (secondProgressCurrentValue / 100))}deg 360deg)`;
|
|
39
|
+
progressRadial.style.background = backgroundStyle;
|
|
40
|
+
}, 13);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
progressRadial.setAttribute('data-progress-radial-initialized', 'true');
|
|
44
|
+
}
|
|
45
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export const initRange = (rangeContainer: HTMLElement) => {
|
|
2
|
+
|
|
3
|
+
let HTMLInputRangeMin: HTMLInputElement = rangeContainer.querySelector(".range-cursor-min");
|
|
4
|
+
let HTMLInputRangeMax: HTMLInputElement = rangeContainer.querySelector(".range-cursor-max");
|
|
5
|
+
let track: HTMLDivElement = rangeContainer.querySelector(".range-track");
|
|
6
|
+
let valueMin: HTMLHtmlElement = rangeContainer.querySelector(".range-value-min");
|
|
7
|
+
let valueMax: HTMLHtmlElement = rangeContainer.querySelector(".range-value-max");
|
|
8
|
+
|
|
9
|
+
let maxValue = HTMLInputRangeMin.max;
|
|
10
|
+
let gap = 0;
|
|
11
|
+
|
|
12
|
+
const setColor = () => {
|
|
13
|
+
let percent1 =
|
|
14
|
+
(Number(HTMLInputRangeMin.value) / Number(maxValue)) * 100;
|
|
15
|
+
let percent2 =
|
|
16
|
+
(Number(HTMLInputRangeMax.value) / Number(maxValue)) * 100;
|
|
17
|
+
track.style.background = `linear-gradient(to right, #E1E1E1 ${percent1}% , #0C7B91 ${percent1}% , #0C7B91 ${percent2}%, #E1E1E1 ${percent2}%) `;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
setColor();
|
|
21
|
+
|
|
22
|
+
HTMLInputRangeMin.addEventListener("input", (e: InputEvent) => {
|
|
23
|
+
const event = e.target as HTMLInputElement;
|
|
24
|
+
if (Number(event.value) < Number(HTMLInputRangeMax.value) - gap) {
|
|
25
|
+
HTMLInputRangeMin.value = event.value;
|
|
26
|
+
} else {
|
|
27
|
+
HTMLInputRangeMin.value = String(
|
|
28
|
+
Number(HTMLInputRangeMax.value) - gap
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
valueMin.textContent = event.value;
|
|
32
|
+
setColor();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
HTMLInputRangeMax.addEventListener("input", (e: InputEvent) => {
|
|
36
|
+
const event = e.target as HTMLInputElement;
|
|
37
|
+
if (Number(event.value) > Number(HTMLInputRangeMin.value) + gap) {
|
|
38
|
+
HTMLInputRangeMax.value = event.value;
|
|
39
|
+
} else {
|
|
40
|
+
HTMLInputRangeMax.value = String(
|
|
41
|
+
Number(HTMLInputRangeMin.value) + gap
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
valueMax.textContent = event.value;
|
|
45
|
+
setColor();
|
|
46
|
+
});
|
|
47
|
+
rangeContainer.setAttribute(`data-ranges-initialized`, 'true')
|
|
48
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const initSegmentedControl = () => {
|
|
2
|
+
const HTMLButtons = document.querySelectorAll(".segmented-control-item");
|
|
3
|
+
|
|
4
|
+
HTMLButtons.forEach((button: HTMLButtonElement) => {
|
|
5
|
+
button.addEventListener("click", function () {
|
|
6
|
+
this.parentElement
|
|
7
|
+
.querySelector(".is-active")
|
|
8
|
+
.classList.remove("is-active");
|
|
9
|
+
|
|
10
|
+
if (!button.classList.contains("is-active")) {
|
|
11
|
+
button.classList.add("is-active");
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
button.setAttribute(`data-segmentedControl-initialized`, 'true')
|
|
15
|
+
});
|
|
16
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export const initSelects = () => {
|
|
2
|
+
const HTMLSelects = document.querySelectorAll('[data-select-name]')
|
|
3
|
+
|
|
4
|
+
if (HTMLSelects) {
|
|
5
|
+
HTMLSelects.forEach((HTMLSelect: HTMLDivElement) => {
|
|
6
|
+
const HTMLLabel = HTMLSelect.querySelector('label')
|
|
7
|
+
if (!HTMLSelect.classList.contains('select-disabled')) {
|
|
8
|
+
const HTMLParentOfSelect = HTMLSelect.parentNode as HTMLElement
|
|
9
|
+
let HTMLOptions = HTMLParentOfSelect.querySelector('[data-is-open-options]')
|
|
10
|
+
|
|
11
|
+
HTMLSelect.addEventListener('click', () => {
|
|
12
|
+
const isOpenOptions = HTMLOptions.getAttribute('data-is-open-options')
|
|
13
|
+
if (isOpenOptions === 'true') HTMLOptions.setAttribute('data-is-open-options', 'false')
|
|
14
|
+
if (isOpenOptions === 'false') HTMLOptions.setAttribute('data-is-open-options', 'true')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
HTMLSelect.addEventListener('blur', () => {
|
|
18
|
+
HTMLOptions.setAttribute('data-is-open-options', 'false')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const options = HTMLOptions.querySelectorAll('[data-option-name]')
|
|
22
|
+
options.forEach((option: HTMLElement) => {
|
|
23
|
+
if (!option.classList.contains('select-options-option-disabled')) {
|
|
24
|
+
option.addEventListener('mousedown', () => {
|
|
25
|
+
// select option
|
|
26
|
+
options.forEach((opt: HTMLElement) => opt.classList.remove('select-options-option-activated'))
|
|
27
|
+
option.classList.add('select-options-option-activated')
|
|
28
|
+
|
|
29
|
+
// insert/update otp
|
|
30
|
+
let HTMLSpan: HTMLSpanElement = HTMLSelect.querySelector('[data-option-selected]')
|
|
31
|
+
if (!HTMLSpan) {
|
|
32
|
+
HTMLSpan = document.createElement('span')
|
|
33
|
+
HTMLSpan.classList.add('select-value')
|
|
34
|
+
if (!HTMLLabel || HTMLLabel === null) HTMLSpan.classList.add('no-label')
|
|
35
|
+
HTMLSelect.appendChild(HTMLSpan)
|
|
36
|
+
}
|
|
37
|
+
HTMLSelect.setAttribute('data-option-selected', option.getAttribute('data-option-name'))
|
|
38
|
+
HTMLSpan.setAttribute('data-option-selected', option.getAttribute('data-option-name'))
|
|
39
|
+
HTMLSpan.textContent = option.getAttribute('data-option-name')
|
|
40
|
+
HTMLParentOfSelect.classList.add('has-dynamic-placeholder')
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
HTMLSelect.setAttribute(`data-selects-initialized`, 'true')
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const initSticky = () => {
|
|
2
|
+
const navbar = document.querySelector('.navbar');
|
|
3
|
+
|
|
4
|
+
const myObserverCallback: any = (event: any) => {
|
|
5
|
+
navbar.classList.toggle('enable-transition', event.intersectionRatio < 1);
|
|
6
|
+
setTimeout(() => {
|
|
7
|
+
event.target.parentNode.classList.toggle('is-sticky', event.intersectionRatio < 1)
|
|
8
|
+
}, 100);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
let observer = new IntersectionObserver(myObserverCallback, { threshold: 1 });
|
|
12
|
+
observer.observe(navbar);
|
|
13
|
+
|
|
14
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const initTableExpansion = () => {
|
|
2
|
+
let expandableRows: NodeListOf<HTMLElement> = document.querySelectorAll('[data-expandable-row]');
|
|
3
|
+
for (let i = 0; i < expandableRows.length; i++) {
|
|
4
|
+
let expandableRow: HTMLElement = expandableRows[i];
|
|
5
|
+
let trigger: HTMLElement = expandableRow.querySelector('[data-expandable-trigger]');
|
|
6
|
+
trigger.addEventListener('click', function () {
|
|
7
|
+
expandableRow.classList.toggle('is-expanded');
|
|
8
|
+
});
|
|
9
|
+
expandableRow.setAttribute(`data-tableexpansion-initialized`, 'true')
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export const initTabs = () => {
|
|
2
|
+
const tabContexts = document.querySelectorAll('[data-tabs-context]')
|
|
3
|
+
|
|
4
|
+
const styleCusto =
|
|
5
|
+
'right: 0;' +
|
|
6
|
+
'padding-left: 16px;' +
|
|
7
|
+
'width: 4.5rem !important;' +
|
|
8
|
+
'background: linear-gradient(90deg, rgba(256,256,256, 0) -25%, white 30%);\n' +
|
|
9
|
+
'background-attachment: local, local, scroll, scroll;'
|
|
10
|
+
|
|
11
|
+
const styledTabs = `
|
|
12
|
+
.tabs {
|
|
13
|
+
padding-right: 2rem;
|
|
14
|
+
}
|
|
15
|
+
`
|
|
16
|
+
|
|
17
|
+
const styleTabAttr = document.createElement('style')
|
|
18
|
+
styleTabAttr.innerText = styledTabs
|
|
19
|
+
|
|
20
|
+
tabContexts.forEach((tabContext) => {
|
|
21
|
+
const tabContextWidth = tabContext.clientWidth
|
|
22
|
+
let tabs = tabContext.querySelector('.tabs')
|
|
23
|
+
if(!tabs) {
|
|
24
|
+
tabs = tabContext.querySelector('[data-real-class*="tabs"]')
|
|
25
|
+
}
|
|
26
|
+
const tabsWidth = tabs.scrollWidth
|
|
27
|
+
|
|
28
|
+
if (tabsWidth > tabContextWidth) {
|
|
29
|
+
if (!tabs.innerHTML.includes('icon is-small is-absolute')) {
|
|
30
|
+
const arrowIcon = `<span class="icon is-small is-absolute" style="${styleCusto}"><i class="tri-arrow-right" aria-hidden=\'true\'></i></span>`
|
|
31
|
+
tabs.innerHTML += arrowIcon
|
|
32
|
+
tabs.appendChild(styleTabAttr)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
let tabsContext = document.querySelectorAll('[data-tabs-context]')
|
|
38
|
+
for (let i = 0; i < tabsContext.length; i++) {
|
|
39
|
+
let tabContext = tabsContext[i]
|
|
40
|
+
let tabs: NodeListOf<HTMLElement> = tabContext.querySelectorAll('[data-tab-navigation]')
|
|
41
|
+
let tabsContent: NodeListOf<HTMLElement> = tabContext.querySelectorAll('[data-tab-content]')
|
|
42
|
+
for (let j = 0; j < tabs.length; j++) {
|
|
43
|
+
let tabElement: HTMLElement = tabs[j]
|
|
44
|
+
let tabContent: HTMLElement = tabsContent[j]
|
|
45
|
+
tabElement.addEventListener('click', function () {
|
|
46
|
+
makeTabActive(tabElement, tabContent)
|
|
47
|
+
})
|
|
48
|
+
tabElement.addEventListener('keyup', (e: KeyboardEvent) => {
|
|
49
|
+
e.preventDefault()
|
|
50
|
+
switch (e.keyCode) {
|
|
51
|
+
case 35: // end key
|
|
52
|
+
makeTabActive(tabs[tabs.length - 1], tabsContent[tabs.length - 1])
|
|
53
|
+
break
|
|
54
|
+
case 36: // home key
|
|
55
|
+
makeTabActive(tabs[0], tabsContent[0])
|
|
56
|
+
break
|
|
57
|
+
case 37: // left arrow
|
|
58
|
+
let previous = (j - 1) % tabs.length
|
|
59
|
+
makeTabActive(tabs[previous], tabsContent[previous])
|
|
60
|
+
break
|
|
61
|
+
case 39: // right arrow
|
|
62
|
+
let next = (j + 1) % tabs.length
|
|
63
|
+
makeTabActive(tabs[next], tabsContent[next])
|
|
64
|
+
break
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Make an element inactive
|
|
71
|
+
*/
|
|
72
|
+
const makeAllTabsInactive = () => {
|
|
73
|
+
for (let i = 0; i < tabs.length; i++) {
|
|
74
|
+
tabs[i].classList.remove('is-active')
|
|
75
|
+
tabs[i].setAttribute('aria-selected', 'false')
|
|
76
|
+
tabs[i].setAttribute('tabindex', '-1')
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for (let j = 0; j < tabsContent.length; j++) {
|
|
80
|
+
tabsContent[j].classList.remove('is-active')
|
|
81
|
+
tabsContent[j].setAttribute('aria-expanded', 'false')
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Make an element active
|
|
87
|
+
* @param { Element } tabElementToMakeActive element to be made active
|
|
88
|
+
* @param tabContentToMakeActive
|
|
89
|
+
*/
|
|
90
|
+
const makeTabActive = (tabElementToMakeActive: HTMLElement, tabContentToMakeActive: HTMLElement) => {
|
|
91
|
+
makeAllTabsInactive()
|
|
92
|
+
tabElementToMakeActive.classList.add('is-active')
|
|
93
|
+
tabElementToMakeActive.setAttribute('aria-selected', 'true')
|
|
94
|
+
tabElementToMakeActive.setAttribute('tabindex', '0')
|
|
95
|
+
tabElementToMakeActive.focus()
|
|
96
|
+
tabContentToMakeActive.classList.add('is-active')
|
|
97
|
+
tabContentToMakeActive.setAttribute('aria-expanded', 'true')
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
tabContext.setAttribute(`data-tab-initialized`, 'true')
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const initTextarea = () => {
|
|
2
|
+
const textareaWrappers = document.querySelectorAll(".textarea-wrapper");
|
|
3
|
+
textareaWrappers.forEach((textareaWrapper: HTMLElement) => {
|
|
4
|
+
const isInitialized = textareaWrapper.getAttribute('data-textarea-initialized');
|
|
5
|
+
if(!isInitialized) {
|
|
6
|
+
const textarea: HTMLTextAreaElement = textareaWrapper.querySelector('textarea.textarea');
|
|
7
|
+
|
|
8
|
+
const counterMaxLength = textarea.getAttribute('maxlength');
|
|
9
|
+
if (counterMaxLength) {
|
|
10
|
+
var currentLength = 0;
|
|
11
|
+
const counter = document.createElement('div');
|
|
12
|
+
counter.classList.add('counter');
|
|
13
|
+
counter.innerHTML = `${currentLength}/${counterMaxLength}`;
|
|
14
|
+
textareaWrapper.appendChild(counter);
|
|
15
|
+
|
|
16
|
+
textarea.addEventListener("input", function (e) {
|
|
17
|
+
currentLength = this.value.length;
|
|
18
|
+
counter.innerHTML = `${currentLength}/${counterMaxLength}`;
|
|
19
|
+
if(currentLength === 10) {
|
|
20
|
+
e.preventDefault();
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
textareaWrapper.setAttribute('data-textarea-initialized', 'true');
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type functionToPlayType = (htmlElement: HTMLElement) => void;
|
|
2
|
+
|
|
3
|
+
export const intersectionObserver = (elementToObserve: HTMLElement, functionToPlay: functionToPlayType) => {
|
|
4
|
+
const observer = new IntersectionObserver((entries) => {
|
|
5
|
+
entries.forEach((entry: any) => {
|
|
6
|
+
if (entry.isIntersecting) {
|
|
7
|
+
functionToPlay(entry.target);
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
observer.observe(elementToObserve);
|
|
13
|
+
}
|
package/tsconfig.json
ADDED
package/vite.config.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import { resolve } from 'path'
|
|
3
|
+
import tsconfigPaths from 'vite-tsconfig-paths'
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [tsconfigPaths()],
|
|
7
|
+
root: resolve(__dirname, 'src/'),
|
|
8
|
+
base: './',
|
|
9
|
+
mode: 'production',
|
|
10
|
+
build: {
|
|
11
|
+
outDir: '../lib',
|
|
12
|
+
lib: {
|
|
13
|
+
entry: resolve(__dirname, 'src/app.ts'),
|
|
14
|
+
name: 'trilogy-ds-vanilla',
|
|
15
|
+
fileName: () => `trilogy-ds-vanilla.js`,
|
|
16
|
+
},
|
|
17
|
+
rollupOptions: {
|
|
18
|
+
input: {
|
|
19
|
+
main: resolve(__dirname, 'src/app.ts'),
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
})
|