lifecycle-timeline 1.2.7 → 1.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/timeline.js +17 -17
- package/dist/timeline.umd.cjs +3 -3
- package/package.json +1 -1
- package/src/index.d.ts +6 -0
package/dist/timeline.js
CHANGED
|
@@ -49,7 +49,7 @@ class v {
|
|
|
49
49
|
* @param {Object} [options.i18n] - Custom translations to merge or override.
|
|
50
50
|
*/
|
|
51
51
|
constructor(t, e, i = {}) {
|
|
52
|
-
this.root = document.getElementById(t), this.root && (this.options = i, this.visibleCount = i.visibleCount || 3, this.showTable = i.showTable !== !1, this.showThemeToggle = i.showThemeToggle !== !1, this.showLegend = i.showLegend !== !1, this.filterVersions = i.filterVersions !== !1, this.splitSupport = i.splitSupport === !0, this.compactMode = i.compactMode === !0, this.showMajorFilter = i.showMajorFilter === !0, this.isExpanded = !1, this.theme = "light", this.filterText = "", this.majorFilterEnabled = !
|
|
52
|
+
this.root = document.getElementById(t), this.root && (this.options = i, this.visibleCount = i.visibleCount || 3, this.showTable = i.showTable !== !1, this.showThemeToggle = i.showThemeToggle !== !1, this.showLegend = i.showLegend !== !1, this.filterVersions = i.filterVersions !== !1, this.splitSupport = i.splitSupport === !0, this.compactMode = i.compactMode === !0, this.showMajorFilter = i.showMajorFilter === !0, this.isExpanded = !1, this.theme = "light", this.filterText = "", this.majorFilterEnabled = i.majorFilterDefault === !0, this.activeHighlight = null, this.root.classList.add("lt-root"), this.root.classList.toggle("lt-mode-split", this.splitSupport), this.root.classList.toggle("lt-mode-overlay", !this.splitSupport), this.root.classList.toggle("lt-mode-compact", this.compactMode), this.root.setAttribute("data-theme", this.theme), this.translations = { ...u, ...i.i18n || {} }, this.locale = i.locale || this.detectLanguage(), this.setupBaseLayout(), this.updateData(e));
|
|
53
53
|
}
|
|
54
54
|
/**
|
|
55
55
|
* Detects the browser language.
|
|
@@ -89,10 +89,10 @@ class v {
|
|
|
89
89
|
*/
|
|
90
90
|
validateData(t) {
|
|
91
91
|
return t.filter((e, i) => {
|
|
92
|
-
const n = ["version", "ossStart", "ossEnd"].filter((
|
|
92
|
+
const n = ["version", "ossStart", "ossEnd"].filter((l) => !e[l]);
|
|
93
93
|
if (n.length > 0)
|
|
94
94
|
return console.warn(`[Timeline] Missing fields for item at index ${i}: ${n.join(", ")}`), !1;
|
|
95
|
-
const a = ["ossStart", "ossEnd", "enterpriseEnd"].filter((
|
|
95
|
+
const a = ["ossStart", "ossEnd", "enterpriseEnd"].filter((l) => e[l]).filter((l) => isNaN(new Date(e[l]).getTime()));
|
|
96
96
|
return a.length > 0 ? (console.warn(`[Timeline] Invalid date format for item "${e.version}": ${a.join(", ")}`), !1) : !0;
|
|
97
97
|
});
|
|
98
98
|
}
|
|
@@ -126,15 +126,15 @@ class v {
|
|
|
126
126
|
* @param {Object} item - Version data.
|
|
127
127
|
*/
|
|
128
128
|
createTableRow(t) {
|
|
129
|
-
const e = this.el("tr", "", this.tableBody), i = Date.now(), s = new Date(t.ossStart).getTime(), n = new Date(t.ossEnd).getTime(),
|
|
129
|
+
const e = this.el("tr", "", this.tableBody), i = Date.now(), s = new Date(t.ossStart).getTime(), n = new Date(t.ossEnd).getTime(), r = t.enterpriseEnd ? new Date(t.enterpriseEnd).getTime() : n, a = i >= s && i <= n ? "lt-status-oss" : i > n && i <= r ? "lt-status-ent" : i > r ? "lt-status-expired" : "", l = this.el("td", "", e);
|
|
130
130
|
let h = `<span class="lt-table-badge ${a}">${t.versionOriginal || t.version}</span>`;
|
|
131
|
-
t.releaseNotesUrl ?
|
|
131
|
+
t.releaseNotesUrl ? l.innerHTML = `<a href="${t.releaseNotesUrl}" target="_blank" class="lt-table-version-link">${h}</a>` : l.innerHTML = h;
|
|
132
132
|
const o = this.el("td", "", e);
|
|
133
133
|
o.textContent = t.ossStart, i > s && (o.className = "lt-past-date");
|
|
134
134
|
const g = this.el("td", "", e);
|
|
135
135
|
g.textContent = t.ossEnd, i > n && (g.className = "lt-past-date");
|
|
136
136
|
const c = this.el("td", "", e);
|
|
137
|
-
return c.textContent = t.enterpriseEnd || t.ossEnd, i >
|
|
137
|
+
return c.textContent = t.enterpriseEnd || t.ossEnd, i > r && (c.className = "lt-past-date"), { el: e, version: t.version.toLowerCase(), versionOriginal: t.versionOriginal || t.version };
|
|
138
138
|
}
|
|
139
139
|
/**
|
|
140
140
|
* Updates table visibility based on filter and visibleCount.
|
|
@@ -188,8 +188,8 @@ class v {
|
|
|
188
188
|
updateTooltipPos(t) {
|
|
189
189
|
const e = this.root.getBoundingClientRect(), i = 12;
|
|
190
190
|
let s = t.clientX - e.left + i, n = t.clientY - e.top + i;
|
|
191
|
-
const
|
|
192
|
-
s +
|
|
191
|
+
const r = this.tooltip.offsetWidth, a = this.tooltip.offsetHeight;
|
|
192
|
+
s + r > this.root.offsetWidth && (s = t.clientX - e.left - r - i), n + a > this.root.offsetHeight && (n = t.clientY - e.top - a - i), this.tooltip.style.left = `${s}px`, this.tooltip.style.top = `${n}px`;
|
|
193
193
|
}
|
|
194
194
|
/**
|
|
195
195
|
* Hides the tooltip.
|
|
@@ -310,7 +310,7 @@ class v {
|
|
|
310
310
|
i.setAttribute("role", "row"), i.style.transitionDelay = `${e * 0.05}s`;
|
|
311
311
|
const s = this.el("div", "lt-version-label", i);
|
|
312
312
|
s.setAttribute("role", "rowheader");
|
|
313
|
-
const n = Date.now(),
|
|
313
|
+
const n = Date.now(), r = new Date(t.ossStart).getTime(), a = new Date(t.ossEnd).getTime(), l = t.enterpriseEnd ? new Date(t.enterpriseEnd).getTime() : a, h = n >= r && n <= a ? "lt-status-oss" : n > a && n <= l ? "lt-status-ent" : n > l ? "lt-status-expired" : "";
|
|
314
314
|
if (h && s.classList.add(h), t.isMajor && s.classList.add("lt-version-major"), t.releaseNotesUrl) {
|
|
315
315
|
const d = this.el("a", "lt-version-link", s);
|
|
316
316
|
d.href = t.releaseNotesUrl, d.target = "_blank", d.innerHTML = this.highlight(t.version), d.title = this.t("notes", { v: t.version }), d.setAttribute("aria-label", this.t("notes", { v: t.version }));
|
|
@@ -331,8 +331,8 @@ class v {
|
|
|
331
331
|
* @returns {HTMLElement} The created bar element.
|
|
332
332
|
*/
|
|
333
333
|
createBar(t, e, i, s, n) {
|
|
334
|
-
const
|
|
335
|
-
o.classList.add(g), o.style.left = `${(
|
|
334
|
+
const r = new Date(e).getTime(), a = new Date(i).getTime(), l = new Date(this.minYear, 0, 1).getTime(), h = new Date(this.maxYear, 11, 31).getTime() - l, o = this.el("div", `lt-bar-segment ${s}`), g = s === "lt-bar-oss" ? "lt-segment-oss" : s === "lt-bar-ent" ? "lt-segment-ent" : "lt-segment-eol";
|
|
335
|
+
o.classList.add(g), o.style.left = `${(r - l) / h * 100}%`, o.style.width = `${(a - r) / h * 100}%`, o.setAttribute("role", "img"), o.setAttribute("aria-label", `${n}: ${t.version} (${e} to ${i})`), o.tabIndex = 0;
|
|
336
336
|
const c = `
|
|
337
337
|
<div class="lt-tooltip-header">${n} - ${t.version}</div>
|
|
338
338
|
<div class="lt-tooltip-date"><strong>Du:</strong> ${e}</div>
|
|
@@ -348,12 +348,12 @@ class v {
|
|
|
348
348
|
*/
|
|
349
349
|
updateVisibility() {
|
|
350
350
|
const t = this.rows.filter((s) => {
|
|
351
|
-
const n = s.version.includes(this.filterText),
|
|
352
|
-
return n &&
|
|
351
|
+
const n = s.version.includes(this.filterText), r = this.majorFilterEnabled ? s.isMajor : !0;
|
|
352
|
+
return n && r;
|
|
353
353
|
});
|
|
354
354
|
this.rows.forEach((s) => {
|
|
355
|
-
const n = s.el.querySelector(".lt-version-label"),
|
|
356
|
-
|
|
355
|
+
const n = s.el.querySelector(".lt-version-label"), r = n.querySelector(".lt-version-link");
|
|
356
|
+
r ? r.innerHTML = this.highlight(s.versionOriginal || s.version) : n.innerHTML = this.highlight(s.versionOriginal || s.version), s.el.classList.remove("lt-row-visible"), s.el.classList.add("lt-row-hidden");
|
|
357
357
|
});
|
|
358
358
|
const e = this.filterText === "" && t.length > this.visibleCount;
|
|
359
359
|
if ((e && !this.isExpanded ? t.slice(0, this.visibleCount) : t).forEach((s) => {
|
|
@@ -373,8 +373,8 @@ class v {
|
|
|
373
373
|
if (i < 0 || i > e) return;
|
|
374
374
|
const s = (/* @__PURE__ */ new Date()).toISOString().split("T")[0], n = this.el("div", "lt-current-date-indicator", this.indicators);
|
|
375
375
|
n.style.left = `${i / e * 100}%`, n.setAttribute("role", "separator"), n.setAttribute("aria-label", this.t("today", { date: s }));
|
|
376
|
-
const
|
|
377
|
-
|
|
376
|
+
const r = this.el("div", "lt-current-date-badge", n);
|
|
377
|
+
r.textContent = s, r.setAttribute("aria-hidden", "true");
|
|
378
378
|
}
|
|
379
379
|
}
|
|
380
380
|
export {
|
package/dist/timeline.umd.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
(function(u,b){typeof exports=="object"&&typeof module<"u"?module.exports=b():typeof define=="function"&&define.amd?define(b):(u=typeof globalThis<"u"?globalThis:u||self,u.Timeline=b())})(this,(function(){"use strict";const u={en:{filter:"Filter versions...",oss:"OSS Support",ent:"Enterprise Support",eol:"Out of Support",less:"Show Less",more:"Show {n} more versions",notes:"View Release Notes for {v}",dark:"Toggle Dark Mode",ossDesc:"Free security updates and bugfixes.",entDesc:"Expert support during OSS plus extended support after EOL.",eolDesc:"End of life. No further updates are provided.",today:"Today's date: {date}",branch:"Branch",initial:"Initial Release",ossEnd:"End OSS",entEnd:"End Enterprise *",majorOnly:"Major versions only"},fr:{filter:"Filtrer les versions...",oss:"Support OSS",ent:"Support Entreprise",eol:"Fin de support",less:"Voir moins",more:"Voir {n} versions supplémentaires",notes:"Voir les notes de version pour {v}",dark:"Changer le mode sombre",ossDesc:"Mises à jour de sécurité et corrections de bugs gratuites.",entDesc:"Support pendant la période OSS plus support étendu après.",eolDesc:"Version en fin de vie. Plus de mises à jour.",today:"Date du jour : {date}",branch:"Version",initial:"Sortie initiale",ossEnd:"Fin OSS",entEnd:"Fin Entreprise *",majorOnly:"Versions majeures uniquement"}};class b{constructor(t,e,i={}){this.root=document.getElementById(t),this.root&&(this.options=i,this.visibleCount=i.visibleCount||3,this.showTable=i.showTable!==!1,this.showThemeToggle=i.showThemeToggle!==!1,this.showLegend=i.showLegend!==!1,this.filterVersions=i.filterVersions!==!1,this.splitSupport=i.splitSupport===!0,this.compactMode=i.compactMode===!0,this.showMajorFilter=i.showMajorFilter===!0,this.isExpanded=!1,this.theme="light",this.filterText="",this.majorFilterEnabled=!1,this.activeHighlight=null,this.root.classList.add("lt-root"),this.root.classList.toggle("lt-mode-split",this.splitSupport),this.root.classList.toggle("lt-mode-overlay",!this.splitSupport),this.root.classList.toggle("lt-mode-compact",this.compactMode),this.root.setAttribute("data-theme",this.theme),this.translations={...u,...i.i18n||{}},this.locale=i.locale||this.detectLanguage(),this.setupBaseLayout(),this.updateData(e))}detectLanguage(){const t=(navigator.language||"en").split("-")[0];return this.translations[t]?t:"en"}t(t,e={}){let i=(this.translations[this.locale]||this.translations.en)[t]||t;return Object.keys(e).forEach(s=>i=i.replace(`{${s}}`,e[s])),i}setupBaseLayout(){this.root.innerHTML="",this.root.setAttribute("role","application"),this.root.setAttribute("aria-label","Product Lifecycle Timeline"),this.renderToolbar(),this.showThemeToggle&&this.renderThemeToggle(),this.showTable&&(this.tableContainer=this.el("div","lt-table-container",this.root)),this.wrapper=this.el("div","lt-wrapper",this.root),this.wrapper.setAttribute("role","grid"),this.wrapper.setAttribute("aria-readonly","true"),this.axis=this.el("div","lt-axis",this.wrapper),this.axis.setAttribute("role","row"),this.tracks=this.el("div","lt-tracks",this.wrapper),this.showLegend&&(this.legendContainer=this.el("div","lt-legend-container",this.wrapper))}updateData(t){this.data=this.validateData(t||[]),this.calculateTimeRange(),this.render()}validateData(t){return t.filter((e,i)=>{const n=["version","ossStart","ossEnd"].filter(r=>!e[r]);if(n.length>0)return console.warn(`[Timeline] Missing fields for item at index ${i}: ${n.join(", ")}`),!1;const a=["ossStart","ossEnd","enterpriseEnd"].filter(r=>e[r]).filter(r=>isNaN(new Date(e[r]).getTime()));return a.length>0?(console.warn(`[Timeline] Invalid date format for item "${e.version}": ${a.join(", ")}`),!1):!0})}calculateTimeRange(){if(this.currentDate=new Date,!this.data.length){this.minYear=this.currentDate.getFullYear()-1,this.maxYear=this.currentDate.getFullYear()+3;return}const t=this.data.flatMap(e=>[new Date(e.ossStart),new Date(e.enterpriseEnd||e.ossEnd)]);this.minYear=new Date(Math.min(...t)).getFullYear(),this.maxYear=new Date(Math.max(...t)).getFullYear()}renderTable(){const t=this.el("table","lt-table",this.tableContainer);t.setAttribute("aria-label","Project support");const e=this.el("thead","",t),i=this.el("tr","",e);[this.t("branch"),this.t("initial"),this.t("ossEnd"),this.t("entEnd")].forEach(s=>{this.el("th","",i).textContent=s}),this.tableBody=this.el("tbody","",t),this.tableRows=this.data.map(s=>this.createTableRow(s)),this.tableToggleContainer=this.el("div","lt-table-toggle",this.tableContainer),this.updateTableVisibility()}createTableRow(t){const e=this.el("tr","",this.tableBody),i=Date.now(),s=new Date(t.ossStart).getTime(),n=new Date(t.ossEnd).getTime(),l=t.enterpriseEnd?new Date(t.enterpriseEnd).getTime():n,a=i>=s&&i<=n?"lt-status-oss":i>n&&i<=l?"lt-status-ent":i>l?"lt-status-expired":"",r=this.el("td","",e);let h=`<span class="lt-table-badge ${a}">${t.versionOriginal||t.version}</span>`;t.releaseNotesUrl?r.innerHTML=`<a href="${t.releaseNotesUrl}" target="_blank" class="lt-table-version-link">${h}</a>`:r.innerHTML=h;const o=this.el("td","",e);o.textContent=t.ossStart,i>s&&(o.className="lt-past-date");const g=this.el("td","",e);g.textContent=t.ossEnd,i>n&&(g.className="lt-past-date");const c=this.el("td","",e);return c.textContent=t.enterpriseEnd||t.ossEnd,i>l&&(c.className="lt-past-date"),{el:e,version:t.version.toLowerCase(),versionOriginal:t.versionOriginal||t.version}}updateTableVisibility(){const t=this.tableRows.filter(s=>s.version.includes(this.filterText));this.tableRows.forEach(s=>{const n=s.el.querySelector(".lt-table-badge");n.innerHTML=this.highlight(s.versionOriginal||s.version),s.el.classList.remove("lt-row-visible"),s.el.classList.add("lt-row-hidden")});const e=this.filterText===""&&t.length>this.visibleCount;if((e&&!this.isExpanded?t.slice(0,this.visibleCount):t).forEach(s=>{s.el.classList.remove("lt-row-hidden"),s.el.classList.add("lt-row-visible")}),this.tableToggleContainer.innerHTML="",e){const s=this.el("button","lt-toggle-btn lt-table-toggle",this.tableToggleContainer),n=`<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="${this.isExpanded?"18 15 12 9 6 15":"6 9 12 15 18 9"}"></polyline></svg>`;s.innerHTML=this.isExpanded?`${this.t("less")} ${n}`:`${this.t("more",{n:t.length-this.visibleCount})} ${n}`,s.onclick=()=>{this.isExpanded=!this.isExpanded,this.updateVisibility()}}}render(){this.showTable&&(this.tableContainer.innerHTML=""),this.axis.innerHTML="",this.tracks.innerHTML="",this.showLegend&&(this.legendContainer.innerHTML=""),this.showTable&&this.renderTable(),this.renderAxis(),this.grid=this.el("div","lt-grid-lines-container",this.tracks),this.indicators=this.el("div","lt-indicators-container",this.tracks),this.renderGrid(),this.renderCurrentDateLine(),this.rows=this.data.map((t,e)=>this.createRow(t,e)),this.toggleContainer=this.el("div","lt-more-toggle",this.tracks,{paddingTop:"10px",display:"flex",justifyContent:"center",position:"relative",zIndex:"10"}),this.updateVisibility(),this.showLegend&&this.renderLegend(),this.setupTooltip()}setupTooltip(){this.tooltip&&this.tooltip.remove(),this.tooltip=this.el("div","lt-tooltip",this.root),this.tooltip.style.display="none",this.tooltip.setAttribute("role","tooltip")}showTooltip(t,e){this.tooltip.innerHTML=e,this.tooltip.style.display="block",this.updateTooltipPos(t)}updateTooltipPos(t){const e=this.root.getBoundingClientRect(),i=12;let s=t.clientX-e.left+i,n=t.clientY-e.top+i;const l=this.tooltip.offsetWidth,a=this.tooltip.offsetHeight;s+l>this.root.offsetWidth&&(s=t.clientX-e.left-l-i),n+a>this.root.offsetHeight&&(n=t.clientY-e.top-a-i),this.tooltip.style.left=`${s}px`,this.tooltip.style.top=`${n}px`}hideTooltip(){this.tooltip&&(this.tooltip.style.display="none")}highlight(t){if(!this.filterText)return t;try{const e=new RegExp(`(${this.filterText})`,"gi");return t.replace(e,'<mark class="lt-highlight-match">$1</mark>')}catch{return t}}el(t,e,i,s={}){const n=document.createElement(t);return e&&(n.className=e),Object.assign(n.style,s),i&&i.appendChild(n),n}renderToolbar(){const t=this.el("div","lt-toolbar",this.root);if(this.filterVersions){const e=this.el("div","lt-filter-container",t);e.innerHTML='<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>';const i=this.el("input","lt-filter-input",e);i.placeholder=this.t("filter"),i.value=this.filterText,i.setAttribute("aria-label",this.t("filter")),i.oninput=s=>{this.filterText=s.target.value.toLowerCase().trim(),this.updateVisibility()}}if(this.showMajorFilter){const e=this.el("label","lt-checkbox-label",t),i=this.el("input","",e);i.type="checkbox",i.checked=this.majorFilterEnabled,i.onchange=n=>{this.majorFilterEnabled=n.target.checked,this.updateVisibility()};const s=this.el("span","",e);s.textContent=this.t("majorOnly")}}renderThemeToggle(){const t=this.el("button","lt-theme-toggle-btn",this.root);t.title=this.t("dark"),t.setAttribute("aria-label",this.t("dark"));const e={moon:'<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>',sun:'<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>'};t.innerHTML=this.theme==="dark"?e.sun:e.moon,t.onclick=()=>{this.theme=this.theme==="light"?"dark":"light",this.root.setAttribute("data-theme",this.theme),t.innerHTML=this.theme==="dark"?e.sun:e.moon,t.setAttribute("aria-pressed",this.theme==="dark")}}renderLegend(){this.legendContainer.innerHTML="";const t=this.el("div","lt-legend",this.legendContainer);t.setAttribute("role","complementary"),t.setAttribute("aria-label","Support Legend"),["oss","ent","eol"].forEach(e=>{const i=this.el("div",`lt-legend-block ${e==="ent"?"commercial":e}`,t);i.classList.add("lt-legend-item-reactive"),this.activeHighlight===e&&i.classList.add("lt-active-highlight"),i.innerHTML=`
|
|
1
|
+
(function(p,b){typeof exports=="object"&&typeof module<"u"?module.exports=b():typeof define=="function"&&define.amd?define(b):(p=typeof globalThis<"u"?globalThis:p||self,p.Timeline=b())})(this,(function(){"use strict";const p={en:{filter:"Filter versions...",oss:"OSS Support",ent:"Enterprise Support",eol:"Out of Support",less:"Show Less",more:"Show {n} more versions",notes:"View Release Notes for {v}",dark:"Toggle Dark Mode",ossDesc:"Free security updates and bugfixes.",entDesc:"Expert support during OSS plus extended support after EOL.",eolDesc:"End of life. No further updates are provided.",today:"Today's date: {date}",branch:"Branch",initial:"Initial Release",ossEnd:"End OSS",entEnd:"End Enterprise *",majorOnly:"Major versions only"},fr:{filter:"Filtrer les versions...",oss:"Support OSS",ent:"Support Entreprise",eol:"Fin de support",less:"Voir moins",more:"Voir {n} versions supplémentaires",notes:"Voir les notes de version pour {v}",dark:"Changer le mode sombre",ossDesc:"Mises à jour de sécurité et corrections de bugs gratuites.",entDesc:"Support pendant la période OSS plus support étendu après.",eolDesc:"Version en fin de vie. Plus de mises à jour.",today:"Date du jour : {date}",branch:"Version",initial:"Sortie initiale",ossEnd:"Fin OSS",entEnd:"Fin Entreprise *",majorOnly:"Versions majeures uniquement"}};class b{constructor(t,e,i={}){this.root=document.getElementById(t),this.root&&(this.options=i,this.visibleCount=i.visibleCount||3,this.showTable=i.showTable!==!1,this.showThemeToggle=i.showThemeToggle!==!1,this.showLegend=i.showLegend!==!1,this.filterVersions=i.filterVersions!==!1,this.splitSupport=i.splitSupport===!0,this.compactMode=i.compactMode===!0,this.showMajorFilter=i.showMajorFilter===!0,this.isExpanded=!1,this.theme="light",this.filterText="",this.majorFilterEnabled=i.majorFilterDefault===!0,this.activeHighlight=null,this.root.classList.add("lt-root"),this.root.classList.toggle("lt-mode-split",this.splitSupport),this.root.classList.toggle("lt-mode-overlay",!this.splitSupport),this.root.classList.toggle("lt-mode-compact",this.compactMode),this.root.setAttribute("data-theme",this.theme),this.translations={...p,...i.i18n||{}},this.locale=i.locale||this.detectLanguage(),this.setupBaseLayout(),this.updateData(e))}detectLanguage(){const t=(navigator.language||"en").split("-")[0];return this.translations[t]?t:"en"}t(t,e={}){let i=(this.translations[this.locale]||this.translations.en)[t]||t;return Object.keys(e).forEach(s=>i=i.replace(`{${s}}`,e[s])),i}setupBaseLayout(){this.root.innerHTML="",this.root.setAttribute("role","application"),this.root.setAttribute("aria-label","Product Lifecycle Timeline"),this.renderToolbar(),this.showThemeToggle&&this.renderThemeToggle(),this.showTable&&(this.tableContainer=this.el("div","lt-table-container",this.root)),this.wrapper=this.el("div","lt-wrapper",this.root),this.wrapper.setAttribute("role","grid"),this.wrapper.setAttribute("aria-readonly","true"),this.axis=this.el("div","lt-axis",this.wrapper),this.axis.setAttribute("role","row"),this.tracks=this.el("div","lt-tracks",this.wrapper),this.showLegend&&(this.legendContainer=this.el("div","lt-legend-container",this.wrapper))}updateData(t){this.data=this.validateData(t||[]),this.calculateTimeRange(),this.render()}validateData(t){return t.filter((e,i)=>{const n=["version","ossStart","ossEnd"].filter(l=>!e[l]);if(n.length>0)return console.warn(`[Timeline] Missing fields for item at index ${i}: ${n.join(", ")}`),!1;const a=["ossStart","ossEnd","enterpriseEnd"].filter(l=>e[l]).filter(l=>isNaN(new Date(e[l]).getTime()));return a.length>0?(console.warn(`[Timeline] Invalid date format for item "${e.version}": ${a.join(", ")}`),!1):!0})}calculateTimeRange(){if(this.currentDate=new Date,!this.data.length){this.minYear=this.currentDate.getFullYear()-1,this.maxYear=this.currentDate.getFullYear()+3;return}const t=this.data.flatMap(e=>[new Date(e.ossStart),new Date(e.enterpriseEnd||e.ossEnd)]);this.minYear=new Date(Math.min(...t)).getFullYear(),this.maxYear=new Date(Math.max(...t)).getFullYear()}renderTable(){const t=this.el("table","lt-table",this.tableContainer);t.setAttribute("aria-label","Project support");const e=this.el("thead","",t),i=this.el("tr","",e);[this.t("branch"),this.t("initial"),this.t("ossEnd"),this.t("entEnd")].forEach(s=>{this.el("th","",i).textContent=s}),this.tableBody=this.el("tbody","",t),this.tableRows=this.data.map(s=>this.createTableRow(s)),this.tableToggleContainer=this.el("div","lt-table-toggle",this.tableContainer),this.updateTableVisibility()}createTableRow(t){const e=this.el("tr","",this.tableBody),i=Date.now(),s=new Date(t.ossStart).getTime(),n=new Date(t.ossEnd).getTime(),r=t.enterpriseEnd?new Date(t.enterpriseEnd).getTime():n,a=i>=s&&i<=n?"lt-status-oss":i>n&&i<=r?"lt-status-ent":i>r?"lt-status-expired":"",l=this.el("td","",e);let h=`<span class="lt-table-badge ${a}">${t.versionOriginal||t.version}</span>`;t.releaseNotesUrl?l.innerHTML=`<a href="${t.releaseNotesUrl}" target="_blank" class="lt-table-version-link">${h}</a>`:l.innerHTML=h;const o=this.el("td","",e);o.textContent=t.ossStart,i>s&&(o.className="lt-past-date");const g=this.el("td","",e);g.textContent=t.ossEnd,i>n&&(g.className="lt-past-date");const c=this.el("td","",e);return c.textContent=t.enterpriseEnd||t.ossEnd,i>r&&(c.className="lt-past-date"),{el:e,version:t.version.toLowerCase(),versionOriginal:t.versionOriginal||t.version}}updateTableVisibility(){const t=this.tableRows.filter(s=>s.version.includes(this.filterText));this.tableRows.forEach(s=>{const n=s.el.querySelector(".lt-table-badge");n.innerHTML=this.highlight(s.versionOriginal||s.version),s.el.classList.remove("lt-row-visible"),s.el.classList.add("lt-row-hidden")});const e=this.filterText===""&&t.length>this.visibleCount;if((e&&!this.isExpanded?t.slice(0,this.visibleCount):t).forEach(s=>{s.el.classList.remove("lt-row-hidden"),s.el.classList.add("lt-row-visible")}),this.tableToggleContainer.innerHTML="",e){const s=this.el("button","lt-toggle-btn lt-table-toggle",this.tableToggleContainer),n=`<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="${this.isExpanded?"18 15 12 9 6 15":"6 9 12 15 18 9"}"></polyline></svg>`;s.innerHTML=this.isExpanded?`${this.t("less")} ${n}`:`${this.t("more",{n:t.length-this.visibleCount})} ${n}`,s.onclick=()=>{this.isExpanded=!this.isExpanded,this.updateVisibility()}}}render(){this.showTable&&(this.tableContainer.innerHTML=""),this.axis.innerHTML="",this.tracks.innerHTML="",this.showLegend&&(this.legendContainer.innerHTML=""),this.showTable&&this.renderTable(),this.renderAxis(),this.grid=this.el("div","lt-grid-lines-container",this.tracks),this.indicators=this.el("div","lt-indicators-container",this.tracks),this.renderGrid(),this.renderCurrentDateLine(),this.rows=this.data.map((t,e)=>this.createRow(t,e)),this.toggleContainer=this.el("div","lt-more-toggle",this.tracks,{paddingTop:"10px",display:"flex",justifyContent:"center",position:"relative",zIndex:"10"}),this.updateVisibility(),this.showLegend&&this.renderLegend(),this.setupTooltip()}setupTooltip(){this.tooltip&&this.tooltip.remove(),this.tooltip=this.el("div","lt-tooltip",this.root),this.tooltip.style.display="none",this.tooltip.setAttribute("role","tooltip")}showTooltip(t,e){this.tooltip.innerHTML=e,this.tooltip.style.display="block",this.updateTooltipPos(t)}updateTooltipPos(t){const e=this.root.getBoundingClientRect(),i=12;let s=t.clientX-e.left+i,n=t.clientY-e.top+i;const r=this.tooltip.offsetWidth,a=this.tooltip.offsetHeight;s+r>this.root.offsetWidth&&(s=t.clientX-e.left-r-i),n+a>this.root.offsetHeight&&(n=t.clientY-e.top-a-i),this.tooltip.style.left=`${s}px`,this.tooltip.style.top=`${n}px`}hideTooltip(){this.tooltip&&(this.tooltip.style.display="none")}highlight(t){if(!this.filterText)return t;try{const e=new RegExp(`(${this.filterText})`,"gi");return t.replace(e,'<mark class="lt-highlight-match">$1</mark>')}catch{return t}}el(t,e,i,s={}){const n=document.createElement(t);return e&&(n.className=e),Object.assign(n.style,s),i&&i.appendChild(n),n}renderToolbar(){const t=this.el("div","lt-toolbar",this.root);if(this.filterVersions){const e=this.el("div","lt-filter-container",t);e.innerHTML='<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>';const i=this.el("input","lt-filter-input",e);i.placeholder=this.t("filter"),i.value=this.filterText,i.setAttribute("aria-label",this.t("filter")),i.oninput=s=>{this.filterText=s.target.value.toLowerCase().trim(),this.updateVisibility()}}if(this.showMajorFilter){const e=this.el("label","lt-checkbox-label",t),i=this.el("input","",e);i.type="checkbox",i.checked=this.majorFilterEnabled,i.onchange=n=>{this.majorFilterEnabled=n.target.checked,this.updateVisibility()};const s=this.el("span","",e);s.textContent=this.t("majorOnly")}}renderThemeToggle(){const t=this.el("button","lt-theme-toggle-btn",this.root);t.title=this.t("dark"),t.setAttribute("aria-label",this.t("dark"));const e={moon:'<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>',sun:'<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>'};t.innerHTML=this.theme==="dark"?e.sun:e.moon,t.onclick=()=>{this.theme=this.theme==="light"?"dark":"light",this.root.setAttribute("data-theme",this.theme),t.innerHTML=this.theme==="dark"?e.sun:e.moon,t.setAttribute("aria-pressed",this.theme==="dark")}}renderLegend(){this.legendContainer.innerHTML="";const t=this.el("div","lt-legend",this.legendContainer);t.setAttribute("role","complementary"),t.setAttribute("aria-label","Support Legend"),["oss","ent","eol"].forEach(e=>{const i=this.el("div",`lt-legend-block ${e==="ent"?"commercial":e}`,t);i.classList.add("lt-legend-item-reactive"),this.activeHighlight===e&&i.classList.add("lt-active-highlight"),i.innerHTML=`
|
|
2
2
|
<div class="lt-legend-icon" aria-hidden="true"></div>
|
|
3
3
|
<div><h3>${this.t(e)}</h3><p>${this.t(e+"Desc")}</p></div>
|
|
4
|
-
`,i.onclick=()=>this.highlightSegment(e)})}highlightSegment(t){this.activeHighlight=this.activeHighlight===t?null:t,this.root.classList.remove("lt-highlight-oss","lt-highlight-ent","lt-highlight-eol"),this.activeHighlight&&this.root.classList.add(`lt-highlight-${this.activeHighlight}`),this.renderLegend()}renderAxis(){this.el("div","",this.axis,{width:"96px",flexShrink:"0"}).setAttribute("role","presentation");for(let e=this.minYear;e<=this.maxYear;e++){const i=this.el("div","lt-year",this.axis);i.textContent=e,i.setAttribute("role","columnheader")}}renderGrid(){const t=new Date(this.minYear,0,1).getTime(),e=new Date(this.maxYear,11,31).getTime()-t;for(let i=this.minYear;i<=this.maxYear;i++){const s=this.el("div","lt-year-grid-line",this.grid);s.style.left=`${(new Date(i,0,1).getTime()-t)/e*100}%`,s.setAttribute("role","presentation")}}createRow(t,e){const i=this.el("div","lt-row row-entrance",this.tracks);i.setAttribute("role","row"),i.style.transitionDelay=`${e*.05}s`;const s=this.el("div","lt-version-label",i);s.setAttribute("role","rowheader");const n=Date.now(),
|
|
4
|
+
`,i.onclick=()=>this.highlightSegment(e)})}highlightSegment(t){this.activeHighlight=this.activeHighlight===t?null:t,this.root.classList.remove("lt-highlight-oss","lt-highlight-ent","lt-highlight-eol"),this.activeHighlight&&this.root.classList.add(`lt-highlight-${this.activeHighlight}`),this.renderLegend()}renderAxis(){this.el("div","",this.axis,{width:"96px",flexShrink:"0"}).setAttribute("role","presentation");for(let e=this.minYear;e<=this.maxYear;e++){const i=this.el("div","lt-year",this.axis);i.textContent=e,i.setAttribute("role","columnheader")}}renderGrid(){const t=new Date(this.minYear,0,1).getTime(),e=new Date(this.maxYear,11,31).getTime()-t;for(let i=this.minYear;i<=this.maxYear;i++){const s=this.el("div","lt-year-grid-line",this.grid);s.style.left=`${(new Date(i,0,1).getTime()-t)/e*100}%`,s.setAttribute("role","presentation")}}createRow(t,e){const i=this.el("div","lt-row row-entrance",this.tracks);i.setAttribute("role","row"),i.style.transitionDelay=`${e*.05}s`;const s=this.el("div","lt-version-label",i);s.setAttribute("role","rowheader");const n=Date.now(),r=new Date(t.ossStart).getTime(),a=new Date(t.ossEnd).getTime(),l=t.enterpriseEnd?new Date(t.enterpriseEnd).getTime():a,h=n>=r&&n<=a?"lt-status-oss":n>a&&n<=l?"lt-status-ent":n>l?"lt-status-expired":"";if(h&&s.classList.add(h),t.isMajor&&s.classList.add("lt-version-major"),t.releaseNotesUrl){const d=this.el("a","lt-version-link",s);d.href=t.releaseNotesUrl,d.target="_blank",d.innerHTML=this.highlight(t.version),d.title=this.t("notes",{v:t.version}),d.setAttribute("aria-label",this.t("notes",{v:t.version}))}else s.innerHTML=this.highlight(t.version);const o=this.el("div","lt-track-container",i);o.setAttribute("role","gridcell");const g=this.splitSupport?t.ossEnd:t.ossStart,c=t.enterpriseEnd||t.ossEnd,u=new Date(this.maxYear,11,31).toISOString().split("T")[0];return o.appendChild(this.createBar(t,c,u,"lt-bar-eol",this.t("eol"))),o.appendChild(this.createBar(t,g,t.enterpriseEnd||t.ossEnd,"lt-bar-ent",this.t("ent"))),o.appendChild(this.createBar(t,t.ossStart,t.ossEnd,"lt-bar-oss",this.t("oss"))),{el:i,version:t.version.toLowerCase(),versionOriginal:t.version,isMajor:t.isMajor}}createBar(t,e,i,s,n){const r=new Date(e).getTime(),a=new Date(i).getTime(),l=new Date(this.minYear,0,1).getTime(),h=new Date(this.maxYear,11,31).getTime()-l,o=this.el("div",`lt-bar-segment ${s}`),g=s==="lt-bar-oss"?"lt-segment-oss":s==="lt-bar-ent"?"lt-segment-ent":"lt-segment-eol";o.classList.add(g),o.style.left=`${(r-l)/h*100}%`,o.style.width=`${(a-r)/h*100}%`,o.setAttribute("role","img"),o.setAttribute("aria-label",`${n}: ${t.version} (${e} to ${i})`),o.tabIndex=0;const c=`
|
|
5
5
|
<div class="lt-tooltip-header">${n} - ${t.version}</div>
|
|
6
6
|
<div class="lt-tooltip-date"><strong>Du:</strong> ${e}</div>
|
|
7
7
|
<div class="lt-tooltip-date"><strong>Au:</strong> ${i}</div>
|
|
8
|
-
`;return o.onmouseenter=
|
|
8
|
+
`;return o.onmouseenter=u=>this.showTooltip(u,c),o.onmousemove=u=>this.updateTooltipPos(u),o.onmouseleave=()=>this.hideTooltip(),o.onfocus=u=>{const d=o.getBoundingClientRect();this.showTooltip({pageX:d.left+window.scrollX,pageY:d.top+window.scrollY-40},c)},o.onblur=()=>this.hideTooltip(),o}updateVisibility(){const t=this.rows.filter(s=>{const n=s.version.includes(this.filterText),r=this.majorFilterEnabled?s.isMajor:!0;return n&&r});this.rows.forEach(s=>{const n=s.el.querySelector(".lt-version-label"),r=n.querySelector(".lt-version-link");r?r.innerHTML=this.highlight(s.versionOriginal||s.version):n.innerHTML=this.highlight(s.versionOriginal||s.version),s.el.classList.remove("lt-row-visible"),s.el.classList.add("lt-row-hidden")});const e=this.filterText===""&&t.length>this.visibleCount;if((e&&!this.isExpanded?t.slice(0,this.visibleCount):t).forEach(s=>{s.el.classList.remove("lt-row-hidden"),s.el.classList.add("lt-row-visible")}),this.showTable&&this.updateTableVisibility(),this.toggleContainer.innerHTML="",e){const s=this.el("button","lt-toggle-btn",this.toggleContainer),n=`<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="${this.isExpanded?"18 15 12 9 6 15":"6 9 12 15 18 9"}"></polyline></svg>`;s.innerHTML=this.isExpanded?`${this.t("less")} ${n}`:`${this.t("more",{n:t.length-this.visibleCount})} ${n}`,s.setAttribute("aria-expanded",this.isExpanded),s.onclick=()=>{this.isExpanded=!this.isExpanded,this.updateVisibility()}}}renderCurrentDateLine(){const t=new Date(this.minYear,0,1).getTime(),e=new Date(this.maxYear,11,31).getTime()-t,i=Date.now()-t;if(i<0||i>e)return;const s=new Date().toISOString().split("T")[0],n=this.el("div","lt-current-date-indicator",this.indicators);n.style.left=`${i/e*100}%`,n.setAttribute("role","separator"),n.setAttribute("aria-label",this.t("today",{date:s}));const r=this.el("div","lt-current-date-badge",n);r.textContent=s,r.setAttribute("aria-hidden","true")}}return b}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lifecycle-timeline",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.8",
|
|
4
4
|
"description": "A beautiful, premium JS timeline component for visualizing product lifecycles, OSS support, and enterprise support dates.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/timeline.umd.cjs",
|
package/src/index.d.ts
CHANGED
|
@@ -60,6 +60,12 @@ export interface TimelineOptions {
|
|
|
60
60
|
* @default false
|
|
61
61
|
*/
|
|
62
62
|
showMajorFilter?: boolean;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Whether the major version filter runs by default.
|
|
66
|
+
* @default false
|
|
67
|
+
*/
|
|
68
|
+
majorFilterDefault?: boolean;
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
export default class Timeline {
|