lifecycle-timeline 1.2.4 → 1.2.6
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/README.md +3 -0
- package/dist/timeline.css +1 -1
- package/dist/timeline.js +99 -93
- package/dist/timeline.umd.cjs +7 -7
- package/package.json +1 -1
- package/src/index.d.ts +18 -0
package/README.md
CHANGED
|
@@ -78,6 +78,9 @@ new Timeline('timeline-root', data, { visibleCount: 3 });
|
|
|
78
78
|
| `locale` | `string` | `auto` | UI language (`'en'`, `'fr'`). |
|
|
79
79
|
| `i18n` | `object` | `{}` | Custom translations or new languages. |
|
|
80
80
|
| `showTable` | `boolean` | `true` | Shows/hides the summary data table. |
|
|
81
|
+
| `showLegend` | `boolean` | `true` | Shows/hides the legend below the timeline. |
|
|
82
|
+
| `filterVersions` | `boolean` | `true` | Shows/hides the version filter input. |
|
|
83
|
+
| `splitSupport` | `boolean` | `false` | If `true`, Ent. starts after OSS end. If `false`, overlaps. |
|
|
81
84
|
|
|
82
85
|
### 🌐 Internationalization (i18n)
|
|
83
86
|
|
package/dist/timeline.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--bg-page: #f9fafb;--bg-card: #ffffff;--bg-track: #e5e7eb;--text-primary: #1f2937;--text-secondary: #6b7280;--text-inverse: #ffffff;--border-color: #e5e7eb;--line-color: #e5e7eb;--grid-line: #9ca3af;--accent-oss: #99e67d;--accent-ent: #ffe88e;--current-date: #086dc3;--font-family: "Inter", system-ui, -apple-system, sans-serif;--tooltip-bg: #ffffff;--tooltip-shadow: rgba(0, 0, 0, .1)}[data-theme=dark]{--bg-page: #111827;--bg-card: #1f2937;--bg-track: #374151;--text-primary: #f9fafb;--text-secondary: #9ca3af;--border-color: #374151;--line-color: #374151;--grid-line: #6b7280;--tooltip-bg: #1f2937;--tooltip-shadow: rgba(0, 0, 0, .5);--accent-oss: #78bd5d;--accent-ent: #e3c456}body{margin:0;padding:0;background-color:var(--bg-page);font-family:var(--font-family);color:var(--text-primary);display:flex;justify-content:center;align-items:center;min-height:100vh;transition:background-color .3s ease,color .3s ease}.page-container{width:100%;max-width:1200px;padding:2rem;background:var(--bg-card);border-radius:12px;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f;transition:background-color .3s ease}.timeline-wrapper{position:relative;padding-top:40px;padding-bottom:60px;overflow-x:auto;scrollbar-width:thin}.timeline-header{display:flex;position:sticky;left:0;margin-bottom:20px}.timeline-tracks{position:relative;padding-top:20px}.timeline-axis{display:flex;border-bottom:1px solid var(--border-color);margin-bottom:10px;padding-bottom:8px;position:relative}.timeline-year{flex:1;font-size:.875rem;font-weight:600;color:var(--text-secondary);border-left:1px dashed var(--border-color);padding-left:0;text-align:center;box-sizing:border-box}.timeline-year:first-child{border-left:none}.timeline-row{display:flex;align-items:center;margin-bottom:1.5rem;position:relative;height:36px;z-index:1;opacity:0;transform:translateY(10px);transition:opacity .4s ease,transform .4s ease}.timeline-row.row-visible{opacity:1;transform:translateY(0)}.version-label{width:80px;min-width:80px;box-sizing:border-box;padding:4px;border-radius:12px;flex-shrink:0;font-weight:600;font-size:.85rem;color:var(--text-primary);margin-right:16px;text-align:center;background-color:transparent;cursor:pointer;transition:all .3s ease;position:sticky;left:0;z-index:10}.version-label:hover{background-color:var(--bg-track);transform:scale(1.05);box-shadow:0 4px 12px #0000001a}.version-label a.version-link{text-decoration:none;color:inherit;display:block;width:100%;height:100%}.version-label a.version-link:hover{text-decoration:underline;opacity:.8}.status-oss{background-color:var(--accent-oss);color:#000}.status-ent{background-color:var(--accent-ent);color:#000}.status-expired{background-color:var(--bg-track);color:var(--text-secondary)}.track-container{flex-grow:1;position:relative;height:100%;background:var(--bg-track);border-radius:0;overflow:hidden;transition:background-color .3s ease}.bar-segment{position:absolute;height:100%;top:0;transition:opacity .3s ease;display:flex;align-items:center;justify-content:center;color:#fff;font-size:.75rem;font-weight:500;overflow:hidden;white-space:nowrap;box-shadow:0 1px 2px #0000001a}.bar-oss{background:linear-gradient(to bottom,#dcfce7 0%,var(--accent-oss) 100%);z-index:2;border-radius:0;height:66%;top:auto;bottom:0}[data-theme=dark] .bar-oss{background:linear-gradient(to bottom,#a7f3d0 0%,var(--accent-oss) 100%)}.bar-ent{background:linear-gradient(to bottom,#fef9c3 0%,var(--accent-ent) 100%);z-index:1;border-radius:0;opacity:.9}.grid-lines-container{position:absolute;inset:0 0 0 96px;pointer-events:none;z-index:5}.indicators-container{position:absolute;inset:0 0 0 96px;pointer-events:none;z-index:20}.current-date-indicator{position:absolute;top:-30px;bottom:0;width:3px;background-image:linear-gradient(to bottom,var(--current-date) 60%,transparent 60%);background-size:3px 20px;background-repeat:repeat-y;border-left:none;z-index:20;pointer-events:none}@keyframes pulse-blue{0%{box-shadow:0 0 #086dc3b3}70%{box-shadow:0 0 0 6px #086dc300}to{box-shadow:0 0 #086dc300}}.current-date-badge{position:absolute;top:100%;margin-top:8px;left:50%;transform:translate(-50%);background-color:var(--current-date);color:#fff;padding:4px 12px;border-radius:12px;font-size:.75rem;font-weight:600;white-space:nowrap;box-shadow:0 2px 4px #086dc333;z-index:25;animation:pulse-blue 2s infinite}.year-grid-line{position:absolute;top:0;bottom:0;border-left:2px solid var(--grid-line);opacity:1;z-index:5;pointer-events:none}.timeline-tooltip-overlay{position:absolute;background:var(--tooltip-bg);color:var(--text-primary);padding:10px 14px;border-radius:8px;font-size:.85rem;box-shadow:0 10px 15px -3px var(--tooltip-shadow),0 4px 6px -4px var(--tooltip-shadow);border:1px solid var(--border-color);pointer-events:none;z-index:10000;transition:opacity .15s ease-out;line-height:1.4}.tooltip-header{font-weight:700;margin-bottom:4px;color:var(--current-date);text-transform:uppercase;font-size:.75rem;letter-spacing:.05em}.tooltip-date strong{color:var(--text-secondary)}.timeline-row{transition:opacity .3s ease,transform .3s ease,height .3s ease}.timeline-row[style*="display: none"]{opacity:0;transform:translateY(10px)}.bar-segment{transition:transform .2s ease,box-shadow .2s ease}.bar-segment:hover{box-shadow:0 4px 12px #0000001a}.bar-segment:focus-visible{outline:2px solid var(--text-primary);outline-offset:-2px;z-index:100}.track-container{transition:background-color .3s ease}.release-legend{margin:40px auto 0;padding:24px;background-color:var(--bg-card);border:1px solid var(--border-color);border-radius:12px;display:flex;flex-direction:column;gap:16px;max-width:800px}.legend-block{display:flex;align-items:flex-start;gap:12px}.legend-icon{width:20px;height:20px;border-radius:4px;flex-shrink:0;margin-top:2px}.legend-block h3{margin:0 0 4px;font-size:1rem;font-weight:700;color:var(--text-primary)}.legend-block p{margin:0;font-size:.9rem;color:var(--text-secondary);line-height:1.5}.legend-block.oss .legend-icon{background-color:var(--accent-oss)}.legend-block.commercial .legend-icon{background-color:var(--accent-ent)}.legend-block.eol .legend-icon{background-color:var(--bg-track)}.timeline-toolbar{display:flex;justify-content:flex-start;align-items:center;margin-bottom:24px;gap:16px}.timeline-filter-container{display:flex;align-items:center;gap:12px;background:var(--bg-card);border:1px solid var(--border-color);padding:8px 16px;border-radius:24px;max-width:400px;flex-grow:1;transition:all .3s ease;box-shadow:0 2px 4px #0000000d}.timeline-filter-container:focus-within{border-color:var(--current-date);box-shadow:0 8px 20px #086dc31a}.timeline-filter-input{border:none;outline:none;font-size:.95rem;color:var(--text-primary);background:transparent;width:100%}.highlight-match{background-color:#fde68a;color:#92400e;padding:0 2px;border-radius:2px;font-weight:700}.release-legend{display:flex;flex-wrap:wrap;gap:1.5rem;margin-top:2rem;padding-top:1.5rem;border-top:1px solid var(--border-color)}.legend-item-reactive{cursor:pointer;transition:all .2s ease;padding:8px;border-radius:8px;border:1px solid transparent}.legend-item-reactive:hover{background-color:var(--bg-track);transform:translateY(-2px)}.legend-item-reactive.active-highlight{background-color:var(--bg-track);border-color:var(--grid-line);box-shadow:0 2px 4px #0000001a}.bar-segment,.version-label{transition:opacity .3s ease,filter .3s ease}[class*=highlight-oss] .bar-segment:not(.segment-oss),[class*=highlight-oss] .version-label:not(.status-oss){opacity:.3;filter:grayscale(.5)}[class*=highlight-ent] .bar-segment:not(.segment-ent),[class*=highlight-ent] .version-label:not(.status-ent){opacity:.3;filter:grayscale(.5)}[class*=highlight-eol] .bar-segment,[class*=highlight-eol] .version-label:not(.status-expired){opacity:.3;filter:grayscale(.5)}.timeline-toggle-btn{display:flex;align-items:center;gap:8px;background:var(--bg-card);border:1px solid var(--border-color);padding:8px 16px;border-radius:20px;cursor:pointer;font-size:.875rem;font-weight:500;color:var(--text-primary);box-shadow:0 1px 2px #0000000d;transition:all .2s ease}.timeline-toggle-btn:hover{background:var(--bg-page);border-color:var(--text-secondary);transform:translateY(-1px)}.timeline-toggle-btn:focus-visible{outline:2px solid var(--current-date);outline-offset:2px}.theme-toggle-btn{position:absolute;top:0;right:0;background:var(--bg-card);border:1px solid var(--border-color);color:var(--text-primary);width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s ease;z-index:1000;box-shadow:0 4px 6px -1px #0000001a}.theme-toggle-btn:focus-visible{outline:2px solid var(--current-date);outline-offset:2px}#timeline-root{position:relative}.theme-toggle-btn:hover{background-color:var(--bg-track);transform:scale(1.1)}@media(max-width:1024px){.timeline-wrapper{padding-left:0}}@media(max-width:768px){.page-container{padding:1rem}.timeline-toolbar{flex-direction:column;align-items:stretch}.timeline-filter-container{max-width:none}}.timeline-row,.timeline-table tr{transition:opacity .4s ease,transform .4s cubic-bezier(.4,0,.2,1)}.row-hidden{display:none!important;opacity:0;transform:translateY(-10px)}.row-visible{display:flex!important;opacity:1;transform:translateY(0)}.timeline-table tr.row-visible{display:table-row!important}.timeline-tracks,.timeline-table tbody{transition:max-height .5s ease-in-out}.timeline-table-container{margin-top:1rem;margin-bottom:2rem;overflow-x:auto;border-radius:12px;border:1px solid var(--border-color);background-color:var(--bg-card);transition:all .3s ease}.timeline-table{width:100%;border-collapse:collapse;font-size:.85rem;text-align:left}.timeline-table th{background-color:var(--bg-page);color:var(--text-secondary);font-weight:700;padding:14px 16px;border-bottom:1px solid var(--border-color);text-transform:uppercase;font-size:.75rem;letter-spacing:.05em}.timeline-table td{padding:12px 16px;border-bottom:1px solid var(--border-color);color:var(--text-primary);vertical-align:middle}.timeline-table tr:hover td{background-color:var(--bg-page)}.timeline-table tr:last-child td{border-bottom:none}.table-badge{display:inline-block;padding:4px 12px;border-radius:12px;font-size:.85rem;font-weight:600;font-family:var(--font-family);text-align:center;min-width:64px;transition:all .3s ease}.table-version-link{text-decoration:none;color:inherit;display:inline-block}.table-version-link:hover .table-badge{transform:translateY(-1px);box-shadow:0 4px 8px #0000001a}.table-badge.status-oss{background-color:var(--accent-oss);color:#000}.table-badge.status-ent{background-color:var(--accent-ent);color:#000}.table-badge.status-expired{background-color:var(--bg-track);color:var(--text-secondary)}.past-date{color:var(--text-secondary);opacity:.7;font-style:italic}.timeline-table-toggle{display:flex;justify-content:center;padding:10px;background-color:var(--bg-card);border-top:1px solid var(--border-color);border-bottom-left-radius:12px;margin-top:40px}.risk-high{color:#ef4444}.risk-medium{color:#f59e0b}.risk-low{color:#10b981}[data-theme=dark] .details-header{background-color:#0f172a}
|
|
1
|
+
.lt-root{--bg-page: #f9fafb;--bg-card: #ffffff;--bg-track: #e5e7eb;--text-primary: #1f2937;--text-secondary: #6b7280;--text-inverse: #ffffff;--border-color: #e5e7eb;--line-color: #e5e7eb;--grid-line: #9ca3af;--accent-oss: #99e67d;--accent-ent: #ffe88e;--current-date: #086dc3;--accent-eol: #ef4444;--font-family: "Inter", system-ui, -apple-system, sans-serif;--tooltip-bg: #ffffff;--tooltip-shadow: rgba(0, 0, 0, .1);transition:background-color .3s ease,color .3s ease;background-color:var(--bg-card);color:var(--text-primary);font-family:var(--font-family);padding:24px;border-radius:16px;overflow:hidden;border:1px solid var(--border-color)}.lt-root[data-theme=dark]{--bg-page: #111827;--bg-card: #1f2937;--bg-track: #374151;--text-primary: #f9fafb;--text-secondary: #9ca3af;--border-color: #374151;--line-color: #374151;--grid-line: #6b7280;--tooltip-bg: #1f2937;--tooltip-shadow: rgba(0, 0, 0, .5);--accent-oss: #78bd5d;--accent-ent: #e3c456;--accent-eol: #f87171}.lt-wrapper{position:relative;padding-top:40px;padding-bottom:60px;overflow-x:auto;scrollbar-width:thin}.lt-header{display:flex;position:sticky;left:0;margin-bottom:20px}.lt-tracks{position:relative;padding-top:20px}.lt-axis{display:flex;border-bottom:1px solid var(--border-color);margin-bottom:10px;padding-bottom:8px;position:relative}.lt-year{flex:1;font-size:.875rem;font-weight:600;color:var(--text-secondary);border-left:1px dashed var(--border-color);padding-left:0;text-align:center;box-sizing:border-box}.lt-year:first-child{border-left:none}.lt-row{display:flex;align-items:center;margin-bottom:1.5rem;position:relative;height:36px;z-index:1;opacity:0;transform:translateY(10px);transition:opacity .4s ease,transform .4s ease}.lt-row.lt-row-visible{opacity:1;transform:translateY(0)}.lt-version-label{width:80px;min-width:80px;box-sizing:border-box;padding:4px;border-radius:12px;flex-shrink:0;font-weight:600;font-size:.85rem;color:var(--text-primary);margin-right:16px;text-align:center;background-color:transparent;cursor:pointer;transition:all .3s ease;position:sticky;left:0;z-index:10}.lt-version-label:hover{background-color:var(--bg-track);transform:scale(1.05);box-shadow:0 4px 12px #0000001a}.lt-version-label a.lt-version-link{text-decoration:none;color:inherit;display:block;width:100%;height:100%}.lt-version-label a.lt-version-link:hover{text-decoration:underline;opacity:.8}.lt-status-oss{background-color:var(--accent-oss);color:#000}.lt-status-ent{background-color:var(--accent-ent);color:#000}.lt-status-expired{background-color:var(--accent-eol);color:#fff}.lt-track-container{flex-grow:1;position:relative;height:100%;background:var(--bg-track);border-radius:0;overflow:hidden;transition:background-color .3s ease}.lt-bar-segment{position:absolute;height:100%;top:0;transition:opacity .3s ease;display:flex;align-items:center;justify-content:center;color:#fff;font-size:.75rem;font-weight:500;overflow:hidden;white-space:nowrap;box-shadow:0 1px 2px #0000001a}.lt-bar-oss{background:linear-gradient(to bottom,#dcfce7 0%,var(--accent-oss) 100%);z-index:2;border-radius:0;height:100%;top:auto;bottom:0}[data-theme=dark] .lt-bar-oss{background:linear-gradient(to bottom,#a7f3d0 0%,var(--accent-oss) 100%)}.lt-bar-ent{background:linear-gradient(to bottom,#fef9c3 0%,var(--accent-ent) 100%);z-index:1;border-radius:0;opacity:.9;height:100%}.lt-bar-eol{background:linear-gradient(to bottom,#fee2e2 0%,var(--accent-eol) 100%);z-index:0;border-radius:0;opacity:.8}.lt-grid-lines-container{position:absolute;inset:0 0 0 96px;pointer-events:none;z-index:5}.lt-indicators-container{position:absolute;inset:0 0 0 96px;pointer-events:none;z-index:20}.lt-current-date-indicator{position:absolute;top:-30px;bottom:0;width:3px;background-image:linear-gradient(to bottom,var(--current-date) 60%,transparent 60%);background-size:3px 20px;background-repeat:repeat-y;border-left:none;z-index:20;pointer-events:none}@keyframes pulse-blue{0%{box-shadow:0 0 #086dc3b3}70%{box-shadow:0 0 0 6px #086dc300}to{box-shadow:0 0 #086dc300}}.lt-current-date-badge{position:absolute;top:100%;margin-top:8px;left:50%;transform:translate(-50%);background-color:var(--current-date);color:#fff;padding:4px 12px;border-radius:12px;font-size:.75rem;font-weight:600;white-space:nowrap;box-shadow:0 2px 4px #086dc333;z-index:25;animation:pulse-blue 2s infinite}.lt-year-grid-line{position:absolute;top:0;bottom:0;border-left:2px solid var(--grid-line);opacity:1;z-index:5;pointer-events:none}.lt-tooltip{position:absolute;background:var(--tooltip-bg);color:var(--text-primary);padding:10px 14px;border-radius:8px;font-size:.85rem;box-shadow:0 10px 15px -3px var(--tooltip-shadow),0 4px 6px -4px var(--tooltip-shadow);border:1px solid var(--border-color);pointer-events:none;z-index:10000;transition:opacity .15s ease-out;line-height:1.4}.lt-tooltip-header{font-weight:700;margin-bottom:4px;color:var(--current-date);text-transform:uppercase;font-size:.75rem;letter-spacing:.05em}.lt-tooltip-date strong{color:var(--text-secondary)}.lt-row{transition:opacity .3s ease,transform .3s ease,height .3s ease}.lt-row[style*="display: none"]{opacity:0;transform:translateY(10px)}.lt-bar-segment{transition:transform .2s ease,box-shadow .2s ease}.lt-bar-segment:hover{box-shadow:0 4px 12px #0000001a}.lt-bar-segment:focus-visible{outline:2px solid var(--text-primary);outline-offset:-2px;z-index:100}.lt-track-container{transition:background-color .3s ease}.lt-legend{margin:40px auto 0;padding:24px;background-color:var(--bg-card);border:1px solid var(--border-color);border-radius:12px;display:flex;flex-direction:column;gap:16px;max-width:800px}.lt-legend-block{display:flex;align-items:flex-start;gap:12px}.lt-legend-icon{width:20px;height:20px;border-radius:4px;flex-shrink:0;margin-top:2px}.lt-legend-block h3{margin:0 0 4px;font-size:1rem;font-weight:700;color:var(--text-primary)}.lt-legend-block p{margin:0;font-size:.9rem;color:var(--text-secondary);line-height:1.5}.lt-legend-block.oss .lt-legend-icon{background-color:var(--accent-oss)}.lt-legend-block.commercial .lt-legend-icon{background-color:var(--accent-ent)}.lt-legend-block.eol .lt-legend-icon{background-color:var(--bg-track)}.lt-toolbar{display:flex;justify-content:flex-start;align-items:center;margin-bottom:24px;gap:16px}.lt-filter-container{display:flex;align-items:center;gap:12px;background:var(--bg-card);border:1px solid var(--border-color);padding:8px 16px;border-radius:24px;max-width:400px;flex-grow:1;transition:all .3s ease;box-shadow:0 2px 4px #0000000d}.lt-filter-container:focus-within{border-color:var(--current-date);box-shadow:0 8px 20px #086dc31a}.lt-filter-input{border:none;outline:none;font-size:.95rem;color:var(--text-primary);background:transparent;width:100%}.lt-highlight-match{background-color:#fde68a;color:#92400e;padding:0 2px;border-radius:2px;font-weight:700}.lt-legend{display:flex;flex-wrap:wrap;gap:1.5rem;margin-top:2rem;padding-top:1.5rem;border-top:1px solid var(--border-color)}.lt-legend-item-reactive{cursor:pointer;transition:all .2s ease;padding:8px;border-radius:8px;border:1px solid transparent}.lt-legend-item-reactive:hover{background-color:var(--bg-track);transform:translateY(-2px)}.lt-legend-item-reactive.lt-active-highlight{background-color:var(--bg-track);border-color:var(--grid-line);box-shadow:0 2px 4px #0000001a}.lt-bar-segment,.lt-version-label{transition:opacity .3s ease,filter .3s ease}[class*=lt-highlight-oss] .lt-bar-segment:not(.lt-segment-oss),[class*=lt-highlight-oss] .lt-version-label:not(.lt-status-oss){opacity:.3;filter:grayscale(.5)}[class*=lt-highlight-ent] .lt-bar-segment:not(.lt-segment-ent),[class*=lt-highlight-ent] .lt-version-label:not(.lt-status-ent){opacity:.3;filter:grayscale(.5)}[class*=lt-highlight-eol] .lt-bar-segment,[class*=lt-highlight-eol] .lt-version-label:not(.lt-status-expired){opacity:.3;filter:grayscale(.5)}.lt-toggle-btn{display:flex;align-items:center;gap:8px;background:var(--bg-card);border:1px solid var(--border-color);padding:8px 16px;border-radius:20px;cursor:pointer;font-size:.875rem;font-weight:500;color:var(--text-primary);box-shadow:0 1px 2px #0000000d;transition:all .2s ease}.lt-toggle-btn:hover{background:var(--bg-page);border-color:var(--text-secondary);transform:translateY(-1px)}.lt-toggle-btn:focus-visible{outline:2px solid var(--current-date);outline-offset:2px}.lt-theme-toggle-btn{position:absolute;top:24px;right:24px;background:var(--bg-card);border:1px solid var(--border-color);color:var(--text-primary);width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s ease;z-index:1000;box-shadow:0 4px 6px -1px #0000001a}.lt-theme-toggle-btn:focus-visible{outline:2px solid var(--current-date);outline-offset:2px}.lt-root{position:relative}.lt-theme-toggle-btn:hover{background-color:var(--bg-track);transform:scale(1.1)}@media(max-width:1024px){.lt-wrapper{padding-left:0}}@media(max-width:768px){.page-container{padding:1rem}.lt-toolbar{flex-direction:column;align-items:stretch}.lt-filter-container{max-width:none}}.lt-row,.lt-table tr{transition:opacity .4s ease,transform .4s cubic-bezier(.4,0,.2,1)}.lt-row-hidden{display:none!important;opacity:0;transform:translateY(-10px)}.lt-row-visible{display:flex!important;opacity:1;transform:translateY(0)}.lt-table tr.lt-row-visible{display:table-row!important}.lt-tracks,.lt-table tbody{transition:max-height .5s ease-in-out}.lt-table-container{margin-top:1rem;margin-bottom:2rem;overflow-x:auto;border-radius:12px;border:1px solid var(--border-color);background-color:var(--bg-card);transition:all .3s ease}.lt-table{width:100%;border-collapse:collapse;font-size:.85rem;text-align:left}.lt-table th{background-color:var(--bg-page);color:var(--text-secondary);font-weight:700;padding:14px 16px;border-bottom:1px solid var(--border-color);text-transform:uppercase;font-size:.75rem;letter-spacing:.05em}.lt-table td{padding:12px 16px;border-bottom:1px solid var(--border-color);color:var(--text-primary);vertical-align:middle}.lt-table tr:hover td{background-color:var(--bg-page)}.lt-table tr:last-child td{border-bottom:none}.lt-table-badge{display:inline-block;padding:4px 12px;border-radius:12px;font-size:.85rem;font-weight:600;font-family:var(--font-family);text-align:center;min-width:64px;transition:all .3s ease}.lt-table-version-link{text-decoration:none;color:inherit;display:inline-block}.lt-table-version-link:hover .lt-table-badge{transform:translateY(-1px);box-shadow:0 4px 8px #0000001a}.lt-table-badge.status-oss{background-color:var(--accent-oss);color:#000}.lt-table-badge.status-ent{background-color:var(--accent-ent);color:#000}.lt-table-badge.status-expired{background-color:var(--accent-eol);color:#fff}.lt-past-date{color:var(--text-secondary);opacity:.7;font-style:italic}.lt-table-toggle{display:flex;justify-content:center;padding:10px;background-color:var(--bg-card);border-top:1px solid var(--border-color);border-bottom-left-radius:12px;margin-top:40px}.risk-high{color:#ef4444}.risk-medium{color:#f59e0b}.risk-low{color:#10b981}[data-theme=dark] .details-header{background-color:#0f172a}
|
package/dist/timeline.js
CHANGED
|
@@ -46,8 +46,8 @@ class v {
|
|
|
46
46
|
* @param {string} [options.locale] - Language code (e.g., 'en', 'fr').
|
|
47
47
|
* @param {Object} [options.i18n] - Custom translations to merge or override.
|
|
48
48
|
*/
|
|
49
|
-
constructor(t, e,
|
|
50
|
-
this.root = document.getElementById(t), this.root && (this.options =
|
|
49
|
+
constructor(t, e, i = {}) {
|
|
50
|
+
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.isExpanded = !1, this.theme = "light", this.filterText = "", 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.setAttribute("data-theme", this.theme), this.translations = { ...u, ...i.i18n || {} }, this.locale = i.locale || this.detectLanguage(), this.setupBaseLayout(), this.updateData(e));
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
53
|
* Detects the browser language.
|
|
@@ -64,14 +64,14 @@ class v {
|
|
|
64
64
|
* @returns {string} The translated string.
|
|
65
65
|
*/
|
|
66
66
|
t(t, e = {}) {
|
|
67
|
-
let
|
|
68
|
-
return Object.keys(e).forEach((
|
|
67
|
+
let i = (this.translations[this.locale] || this.translations.en)[t] || t;
|
|
68
|
+
return Object.keys(e).forEach((s) => i = i.replace(`{${s}}`, e[s])), i;
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
71
71
|
* Sets up the initial layout of the timeline.
|
|
72
72
|
*/
|
|
73
73
|
setupBaseLayout() {
|
|
74
|
-
this.root.innerHTML = "", this.root.setAttribute("role", "application"), this.root.setAttribute("aria-label", "Product Lifecycle Timeline"), this.renderToolbar(), this.renderThemeToggle(), this.showTable && (this.tableContainer = this.el("div", "
|
|
74
|
+
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));
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
77
|
* Updates the timeline data and re-renders.
|
|
@@ -86,11 +86,11 @@ class v {
|
|
|
86
86
|
* @returns {Array<Object>} The validated and filtered data array.
|
|
87
87
|
*/
|
|
88
88
|
validateData(t) {
|
|
89
|
-
return t.filter((e,
|
|
90
|
-
const n = ["version", "ossStart", "ossEnd"].filter((
|
|
89
|
+
return t.filter((e, i) => {
|
|
90
|
+
const n = ["version", "ossStart", "ossEnd"].filter((o) => !e[o]);
|
|
91
91
|
if (n.length > 0)
|
|
92
|
-
return console.warn(`[Timeline] Missing fields for item at index ${
|
|
93
|
-
const a = ["ossStart", "ossEnd", "enterpriseEnd"].filter((
|
|
92
|
+
return console.warn(`[Timeline] Missing fields for item at index ${i}: ${n.join(", ")}`), !1;
|
|
93
|
+
const a = ["ossStart", "ossEnd", "enterpriseEnd"].filter((o) => e[o]).filter((o) => isNaN(new Date(e[o]).getTime()));
|
|
94
94
|
return a.length > 0 ? (console.warn(`[Timeline] Invalid date format for item "${e.version}": ${a.join(", ")}`), !1) : !0;
|
|
95
95
|
});
|
|
96
96
|
}
|
|
@@ -112,43 +112,43 @@ class v {
|
|
|
112
112
|
* Renders the data table.
|
|
113
113
|
*/
|
|
114
114
|
renderTable() {
|
|
115
|
-
const t = this.el("table", "
|
|
115
|
+
const t = this.el("table", "lt-table", this.tableContainer);
|
|
116
116
|
t.setAttribute("aria-label", "Project support");
|
|
117
|
-
const e = this.el("thead", "", t),
|
|
118
|
-
[this.t("branch"), this.t("initial"), this.t("ossEnd"), this.t("entEnd")].forEach((
|
|
119
|
-
this.el("th", "",
|
|
120
|
-
}), this.tableBody = this.el("tbody", "", t), this.tableRows = this.data.map((
|
|
117
|
+
const e = this.el("thead", "", t), i = this.el("tr", "", e);
|
|
118
|
+
[this.t("branch"), this.t("initial"), this.t("ossEnd"), this.t("entEnd")].forEach((s) => {
|
|
119
|
+
this.el("th", "", i).textContent = s;
|
|
120
|
+
}), 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();
|
|
121
121
|
}
|
|
122
122
|
/**
|
|
123
123
|
* Creates a row for the data table.
|
|
124
124
|
* @param {Object} item - Version data.
|
|
125
125
|
*/
|
|
126
126
|
createTableRow(t) {
|
|
127
|
-
const e = this.el("tr", "", this.tableBody),
|
|
128
|
-
let
|
|
129
|
-
t.releaseNotesUrl ?
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
127
|
+
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" : "", o = this.el("td", "", e);
|
|
128
|
+
let h = `<span class="lt-table-badge ${a}">${t.versionOriginal || t.version}</span>`;
|
|
129
|
+
t.releaseNotesUrl ? o.innerHTML = `<a href="${t.releaseNotesUrl}" target="_blank" class="lt-table-version-link">${h}</a>` : o.innerHTML = h;
|
|
130
|
+
const l = this.el("td", "", e);
|
|
131
|
+
l.textContent = t.ossStart, i > s && (l.className = "lt-past-date");
|
|
132
|
+
const g = this.el("td", "", e);
|
|
133
|
+
g.textContent = t.ossEnd, i > n && (g.className = "lt-past-date");
|
|
134
134
|
const c = this.el("td", "", e);
|
|
135
|
-
return c.textContent = t.enterpriseEnd || t.ossEnd,
|
|
135
|
+
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 };
|
|
136
136
|
}
|
|
137
137
|
/**
|
|
138
138
|
* Updates table visibility based on filter and visibleCount.
|
|
139
139
|
*/
|
|
140
140
|
updateTableVisibility() {
|
|
141
|
-
const t = this.tableRows.filter((
|
|
142
|
-
this.tableRows.forEach((
|
|
143
|
-
const n =
|
|
144
|
-
n.innerHTML = this.highlight(
|
|
141
|
+
const t = this.tableRows.filter((s) => s.version.includes(this.filterText));
|
|
142
|
+
this.tableRows.forEach((s) => {
|
|
143
|
+
const n = s.el.querySelector(".lt-table-badge");
|
|
144
|
+
n.innerHTML = this.highlight(s.versionOriginal || s.version), s.el.classList.remove("lt-row-visible"), s.el.classList.add("lt-row-hidden");
|
|
145
145
|
});
|
|
146
146
|
const e = this.filterText === "" && t.length > this.visibleCount;
|
|
147
|
-
if ((e && !this.isExpanded ? t.slice(0, this.visibleCount) : t).forEach((
|
|
148
|
-
|
|
147
|
+
if ((e && !this.isExpanded ? t.slice(0, this.visibleCount) : t).forEach((s) => {
|
|
148
|
+
s.el.classList.remove("lt-row-hidden"), s.el.classList.add("lt-row-visible");
|
|
149
149
|
}), this.tableToggleContainer.innerHTML = "", e) {
|
|
150
|
-
const
|
|
151
|
-
|
|
150
|
+
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>`;
|
|
151
|
+
s.innerHTML = this.isExpanded ? `${this.t("less")} ${n}` : `${this.t("more", { n: t.length - this.visibleCount })} ${n}`, s.onclick = () => {
|
|
152
152
|
this.isExpanded = !this.isExpanded, this.updateVisibility();
|
|
153
153
|
};
|
|
154
154
|
}
|
|
@@ -157,19 +157,19 @@ class v {
|
|
|
157
157
|
* Renders the entire timeline.
|
|
158
158
|
*/
|
|
159
159
|
render() {
|
|
160
|
-
this.showTable && (this.tableContainer.innerHTML = ""), this.axis.innerHTML = "", this.tracks.innerHTML = "", this.legendContainer.innerHTML = "", this.showTable && this.renderTable(), this.renderAxis(), this.grid = this.el("div", "grid-lines-container", this.tracks), this.indicators = this.el("div", "indicators-container", this.tracks), this.renderGrid(), this.renderCurrentDateLine(), this.rows = this.data.map((t, e) => this.createRow(t, e)), this.toggleContainer = this.el("div", "
|
|
160
|
+
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, {
|
|
161
161
|
paddingTop: "10px",
|
|
162
162
|
display: "flex",
|
|
163
163
|
justifyContent: "center",
|
|
164
164
|
position: "relative",
|
|
165
165
|
zIndex: "10"
|
|
166
|
-
}), this.updateVisibility(), this.renderLegend(), this.setupTooltip();
|
|
166
|
+
}), this.updateVisibility(), this.showLegend && this.renderLegend(), this.setupTooltip();
|
|
167
167
|
}
|
|
168
168
|
/**
|
|
169
169
|
* Sets up the tooltip overlay.
|
|
170
170
|
*/
|
|
171
171
|
setupTooltip() {
|
|
172
|
-
this.tooltip && this.tooltip.remove(), this.tooltip = this.el("div", "
|
|
172
|
+
this.tooltip && this.tooltip.remove(), this.tooltip = this.el("div", "lt-tooltip", this.root), this.tooltip.style.display = "none", this.tooltip.setAttribute("role", "tooltip");
|
|
173
173
|
}
|
|
174
174
|
/**
|
|
175
175
|
* Shows the tooltip with provided content.
|
|
@@ -184,9 +184,10 @@ class v {
|
|
|
184
184
|
* @param {MouseEvent} e - The mouse event.
|
|
185
185
|
*/
|
|
186
186
|
updateTooltipPos(t) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
187
|
+
const e = this.root.getBoundingClientRect(), i = 12;
|
|
188
|
+
let s = t.clientX - e.left + i, n = t.clientY - e.top + i;
|
|
189
|
+
const r = this.tooltip.offsetWidth, a = this.tooltip.offsetHeight;
|
|
190
|
+
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`;
|
|
190
191
|
}
|
|
191
192
|
/**
|
|
192
193
|
* Hides the tooltip.
|
|
@@ -203,7 +204,7 @@ class v {
|
|
|
203
204
|
if (!this.filterText) return t;
|
|
204
205
|
try {
|
|
205
206
|
const e = new RegExp(`(${this.filterText})`, "gi");
|
|
206
|
-
return t.replace(e, '<mark class="highlight-match">$1</mark>');
|
|
207
|
+
return t.replace(e, '<mark class="lt-highlight-match">$1</mark>');
|
|
207
208
|
} catch {
|
|
208
209
|
return t;
|
|
209
210
|
}
|
|
@@ -216,33 +217,36 @@ class v {
|
|
|
216
217
|
* @param {Object} [styles={}] - Inline styles.
|
|
217
218
|
* @returns {HTMLElement} The created element.
|
|
218
219
|
*/
|
|
219
|
-
el(t, e,
|
|
220
|
+
el(t, e, i, s = {}) {
|
|
220
221
|
const n = document.createElement(t);
|
|
221
|
-
return e && (n.className = e), Object.assign(n.style,
|
|
222
|
+
return e && (n.className = e), Object.assign(n.style, s), i && i.appendChild(n), n;
|
|
222
223
|
}
|
|
223
224
|
/**
|
|
224
225
|
* Renders the toolbar with the filter input.
|
|
225
226
|
*/
|
|
226
227
|
renderToolbar() {
|
|
227
|
-
const t = this.el("div", "
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
228
|
+
const t = this.el("div", "lt-toolbar", this.root);
|
|
229
|
+
if (this.filterVersions) {
|
|
230
|
+
const e = this.el("div", "lt-filter-container", t);
|
|
231
|
+
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>';
|
|
232
|
+
const i = this.el("input", "lt-filter-input", e);
|
|
233
|
+
i.placeholder = this.t("filter"), i.value = this.filterText, i.setAttribute("aria-label", this.t("filter")), i.oninput = (s) => {
|
|
234
|
+
this.filterText = s.target.value.toLowerCase().trim(), this.updateVisibility();
|
|
235
|
+
};
|
|
236
|
+
}
|
|
233
237
|
}
|
|
234
238
|
/**
|
|
235
239
|
* Renders the theme toggle button.
|
|
236
240
|
*/
|
|
237
241
|
renderThemeToggle() {
|
|
238
|
-
const t = this.el("button", "theme-toggle-btn", this.root);
|
|
242
|
+
const t = this.el("button", "lt-theme-toggle-btn", this.root);
|
|
239
243
|
t.title = this.t("dark"), t.setAttribute("aria-label", this.t("dark"));
|
|
240
244
|
const e = {
|
|
241
245
|
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>',
|
|
242
246
|
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>'
|
|
243
247
|
};
|
|
244
248
|
t.innerHTML = this.theme === "dark" ? e.sun : e.moon, t.onclick = () => {
|
|
245
|
-
this.theme = this.theme === "light" ? "dark" : "light",
|
|
249
|
+
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");
|
|
246
250
|
};
|
|
247
251
|
}
|
|
248
252
|
/**
|
|
@@ -250,13 +254,13 @@ class v {
|
|
|
250
254
|
*/
|
|
251
255
|
renderLegend() {
|
|
252
256
|
this.legendContainer.innerHTML = "";
|
|
253
|
-
const t = this.el("div", "
|
|
257
|
+
const t = this.el("div", "lt-legend", this.legendContainer);
|
|
254
258
|
t.setAttribute("role", "complementary"), t.setAttribute("aria-label", "Support Legend"), ["oss", "ent", "eol"].forEach((e) => {
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
<div class="legend-icon" aria-hidden="true"></div>
|
|
259
|
+
const i = this.el("div", `lt-legend-block ${e === "ent" ? "commercial" : e}`, t);
|
|
260
|
+
i.classList.add("lt-legend-item-reactive"), this.activeHighlight === e && i.classList.add("lt-active-highlight"), i.innerHTML = `
|
|
261
|
+
<div class="lt-legend-icon" aria-hidden="true"></div>
|
|
258
262
|
<div><h3>${this.t(e)}</h3><p>${this.t(e + "Desc")}</p></div>
|
|
259
|
-
`,
|
|
263
|
+
`, i.onclick = () => this.highlightSegment(e);
|
|
260
264
|
});
|
|
261
265
|
}
|
|
262
266
|
/**
|
|
@@ -264,7 +268,7 @@ class v {
|
|
|
264
268
|
* @param {string} type - 'oss', 'ent', or 'eol'.
|
|
265
269
|
*/
|
|
266
270
|
highlightSegment(t) {
|
|
267
|
-
this.activeHighlight = this.activeHighlight === t ? null : t, this.root.classList.remove("highlight-oss", "highlight-ent", "highlight-eol"), this.activeHighlight && this.root.classList.add(`highlight-${this.activeHighlight}`), this.renderLegend();
|
|
271
|
+
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();
|
|
268
272
|
}
|
|
269
273
|
/**
|
|
270
274
|
* Renders the year axis.
|
|
@@ -272,8 +276,8 @@ class v {
|
|
|
272
276
|
renderAxis() {
|
|
273
277
|
this.el("div", "", this.axis, { width: "96px", flexShrink: "0" }).setAttribute("role", "presentation");
|
|
274
278
|
for (let e = this.minYear; e <= this.maxYear; e++) {
|
|
275
|
-
const
|
|
276
|
-
|
|
279
|
+
const i = this.el("div", "lt-year", this.axis);
|
|
280
|
+
i.textContent = e, i.setAttribute("role", "columnheader");
|
|
277
281
|
}
|
|
278
282
|
}
|
|
279
283
|
/**
|
|
@@ -281,9 +285,9 @@ class v {
|
|
|
281
285
|
*/
|
|
282
286
|
renderGrid() {
|
|
283
287
|
const t = new Date(this.minYear, 0, 1).getTime(), e = new Date(this.maxYear, 11, 31).getTime() - t;
|
|
284
|
-
for (let
|
|
285
|
-
const
|
|
286
|
-
|
|
288
|
+
for (let i = this.minYear; i <= this.maxYear; i++) {
|
|
289
|
+
const s = this.el("div", "lt-year-grid-line", this.grid);
|
|
290
|
+
s.style.left = `${(new Date(i, 0, 1).getTime() - t) / e * 100}%`, s.setAttribute("role", "presentation");
|
|
287
291
|
}
|
|
288
292
|
}
|
|
289
293
|
/**
|
|
@@ -292,18 +296,20 @@ class v {
|
|
|
292
296
|
* @returns {Object} Metadata about the created row.
|
|
293
297
|
*/
|
|
294
298
|
createRow(t, e) {
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
const n = Date.now(),
|
|
300
|
-
if (
|
|
301
|
-
const
|
|
302
|
-
|
|
299
|
+
const i = this.el("div", "lt-row row-entrance", this.tracks);
|
|
300
|
+
i.setAttribute("role", "row"), i.style.transitionDelay = `${e * 0.05}s`;
|
|
301
|
+
const s = this.el("div", "lt-version-label", i);
|
|
302
|
+
s.setAttribute("role", "rowheader");
|
|
303
|
+
const n = Date.now(), r = new Date(t.ossStart).getTime(), a = new Date(t.ossEnd).getTime(), o = t.enterpriseEnd ? new Date(t.enterpriseEnd).getTime() : a, h = n >= r && n <= a ? "lt-status-oss" : n > a && n <= o ? "lt-status-ent" : n > o ? "lt-status-expired" : "";
|
|
304
|
+
if (h && s.classList.add(h), t.releaseNotesUrl) {
|
|
305
|
+
const d = this.el("a", "lt-version-link", s);
|
|
306
|
+
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 }));
|
|
303
307
|
} else
|
|
304
|
-
|
|
305
|
-
const
|
|
306
|
-
|
|
308
|
+
s.innerHTML = this.highlight(t.version);
|
|
309
|
+
const l = this.el("div", "lt-track-container", i);
|
|
310
|
+
l.setAttribute("role", "gridcell");
|
|
311
|
+
const g = this.splitSupport ? t.ossEnd : t.ossStart, c = t.enterpriseEnd || t.ossEnd, p = new Date(this.maxYear, 11, 31).toISOString().split("T")[0];
|
|
312
|
+
return l.appendChild(this.createBar(t, c, p, "lt-bar-eol", this.t("eol"))), l.appendChild(this.createBar(t, g, t.enterpriseEnd || t.ossEnd, "lt-bar-ent", this.t("ent"))), l.appendChild(this.createBar(t, t.ossStart, t.ossEnd, "lt-bar-oss", this.t("oss"))), { el: i, version: t.version.toLowerCase(), versionOriginal: t.version };
|
|
307
313
|
}
|
|
308
314
|
/**
|
|
309
315
|
* Creates a colored bar segment for the timeline.
|
|
@@ -314,34 +320,34 @@ class v {
|
|
|
314
320
|
* @param {string} label - Support type label for tooltip.
|
|
315
321
|
* @returns {HTMLElement} The created bar element.
|
|
316
322
|
*/
|
|
317
|
-
createBar(t, e,
|
|
318
|
-
const
|
|
319
|
-
|
|
323
|
+
createBar(t, e, i, s, n) {
|
|
324
|
+
const r = new Date(e).getTime(), a = new Date(i).getTime(), o = new Date(this.minYear, 0, 1).getTime(), h = new Date(this.maxYear, 11, 31).getTime() - o, l = 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";
|
|
325
|
+
l.classList.add(g), l.style.left = `${(r - o) / h * 100}%`, l.style.width = `${(a - r) / h * 100}%`, l.setAttribute("role", "img"), l.setAttribute("aria-label", `${n}: ${t.version} (${e} to ${i})`), l.tabIndex = 0;
|
|
320
326
|
const c = `
|
|
321
|
-
<div class="tooltip-header">${n} - ${t.version}</div>
|
|
322
|
-
<div class="tooltip-date"><strong>Du:</strong> ${e}</div>
|
|
323
|
-
<div class="tooltip-date"><strong>Au:</strong> ${
|
|
327
|
+
<div class="lt-tooltip-header">${n} - ${t.version}</div>
|
|
328
|
+
<div class="lt-tooltip-date"><strong>Du:</strong> ${e}</div>
|
|
329
|
+
<div class="lt-tooltip-date"><strong>Au:</strong> ${i}</div>
|
|
324
330
|
`;
|
|
325
|
-
return
|
|
326
|
-
const
|
|
327
|
-
this.showTooltip({ pageX:
|
|
328
|
-
},
|
|
331
|
+
return l.onmouseenter = (p) => this.showTooltip(p, c), l.onmousemove = (p) => this.updateTooltipPos(p), l.onmouseleave = () => this.hideTooltip(), l.onfocus = (p) => {
|
|
332
|
+
const d = l.getBoundingClientRect();
|
|
333
|
+
this.showTooltip({ pageX: d.left + window.scrollX, pageY: d.top + window.scrollY - 40 }, c);
|
|
334
|
+
}, l.onblur = () => this.hideTooltip(), l;
|
|
329
335
|
}
|
|
330
336
|
/**
|
|
331
337
|
* Updates visibility of rows based on filtering and expansion state.
|
|
332
338
|
*/
|
|
333
339
|
updateVisibility() {
|
|
334
|
-
const t = this.rows.filter((
|
|
335
|
-
this.rows.forEach((
|
|
336
|
-
const n =
|
|
337
|
-
|
|
340
|
+
const t = this.rows.filter((s) => s.version.includes(this.filterText));
|
|
341
|
+
this.rows.forEach((s) => {
|
|
342
|
+
const n = s.el.querySelector(".lt-version-label"), r = n.querySelector(".lt-version-link");
|
|
343
|
+
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");
|
|
338
344
|
});
|
|
339
345
|
const e = this.filterText === "" && t.length > this.visibleCount;
|
|
340
|
-
if ((e && !this.isExpanded ? t.slice(0, this.visibleCount) : t).forEach((
|
|
341
|
-
|
|
346
|
+
if ((e && !this.isExpanded ? t.slice(0, this.visibleCount) : t).forEach((s) => {
|
|
347
|
+
s.el.classList.remove("lt-row-hidden"), s.el.classList.add("lt-row-visible");
|
|
342
348
|
}), this.showTable && this.updateTableVisibility(), this.toggleContainer.innerHTML = "", e) {
|
|
343
|
-
const
|
|
344
|
-
|
|
349
|
+
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>`;
|
|
350
|
+
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 = () => {
|
|
345
351
|
this.isExpanded = !this.isExpanded, this.updateVisibility();
|
|
346
352
|
};
|
|
347
353
|
}
|
|
@@ -350,12 +356,12 @@ class v {
|
|
|
350
356
|
* Renders the vertical line indicating current date.
|
|
351
357
|
*/
|
|
352
358
|
renderCurrentDateLine() {
|
|
353
|
-
const t = new Date(this.minYear, 0, 1).getTime(), e = new Date(this.maxYear, 11, 31).getTime() - t,
|
|
354
|
-
if (
|
|
355
|
-
const
|
|
356
|
-
n.style.left = `${
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
+
const t = new Date(this.minYear, 0, 1).getTime(), e = new Date(this.maxYear, 11, 31).getTime() - t, i = Date.now() - t;
|
|
360
|
+
if (i < 0 || i > e) return;
|
|
361
|
+
const s = (/* @__PURE__ */ new Date()).toISOString().split("T")[0], n = this.el("div", "lt-current-date-indicator", this.indicators);
|
|
362
|
+
n.style.left = `${i / e * 100}%`, n.setAttribute("role", "separator"), n.setAttribute("aria-label", this.t("today", { date: s }));
|
|
363
|
+
const r = this.el("div", "lt-current-date-badge", n);
|
|
364
|
+
r.textContent = s, r.setAttribute("aria-hidden", "true");
|
|
359
365
|
}
|
|
360
366
|
}
|
|
361
367
|
export {
|
package/dist/timeline.umd.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
(function(
|
|
2
|
-
<div class="legend-icon" aria-hidden="true"></div>
|
|
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 *"},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 *"}};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.isExpanded=!1,this.theme="light",this.filterText="",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.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()}}}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
|
+
<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
|
-
`,
|
|
5
|
-
<div class="tooltip-header">${n} - ${t.version}</div>
|
|
6
|
-
<div class="tooltip-date"><strong>Du:</strong> ${e}</div>
|
|
7
|
-
<div class="tooltip-date"><strong>Au:</strong> ${
|
|
8
|
-
`;return
|
|
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(),l=new Date(t.ossStart).getTime(),a=new Date(t.ossEnd).getTime(),r=t.enterpriseEnd?new Date(t.enterpriseEnd).getTime():a,h=n>=l&&n<=a?"lt-status-oss":n>a&&n<=r?"lt-status-ent":n>r?"lt-status-expired":"";if(h&&s.classList.add(h),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,p=new Date(this.maxYear,11,31).toISOString().split("T")[0];return o.appendChild(this.createBar(t,c,p,"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}}createBar(t,e,i,s,n){const l=new Date(e).getTime(),a=new Date(i).getTime(),r=new Date(this.minYear,0,1).getTime(),h=new Date(this.maxYear,11,31).getTime()-r,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=`${(l-r)/h*100}%`,o.style.width=`${(a-l)/h*100}%`,o.setAttribute("role","img"),o.setAttribute("aria-label",`${n}: ${t.version} (${e} to ${i})`),o.tabIndex=0;const c=`
|
|
5
|
+
<div class="lt-tooltip-header">${n} - ${t.version}</div>
|
|
6
|
+
<div class="lt-tooltip-date"><strong>Du:</strong> ${e}</div>
|
|
7
|
+
<div class="lt-tooltip-date"><strong>Au:</strong> ${i}</div>
|
|
8
|
+
`;return o.onmouseenter=p=>this.showTooltip(p,c),o.onmousemove=p=>this.updateTooltipPos(p),o.onmouseleave=()=>this.hideTooltip(),o.onfocus=p=>{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=>s.version.includes(this.filterText));this.rows.forEach(s=>{const n=s.el.querySelector(".lt-version-label"),l=n.querySelector(".lt-version-link");l?l.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 l=this.el("div","lt-current-date-badge",n);l.textContent=s,l.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.6",
|
|
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
|
@@ -29,6 +29,24 @@ export interface TimelineOptions {
|
|
|
29
29
|
* @default true
|
|
30
30
|
*/
|
|
31
31
|
showTable?: boolean;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Whether to show the legend below the timeline.
|
|
35
|
+
* @default true
|
|
36
|
+
*/
|
|
37
|
+
showLegend?: boolean;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Whether to show the version filter input.
|
|
41
|
+
* @default true
|
|
42
|
+
*/
|
|
43
|
+
filterVersions?: boolean;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Whether to show the enterprise bar normally (false) or split after OSS (true).
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
49
|
+
splitSupport?: boolean;
|
|
32
50
|
}
|
|
33
51
|
|
|
34
52
|
export default class Timeline {
|