motimeline 2.3.0 → 2.4.0

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 CHANGED
@@ -111,9 +111,28 @@ import 'motimeline/dist/moTimeline.css';
111
111
  ```js
112
112
  const tl = new MoTimeline(elementOrSelector, options);
113
113
 
114
- tl.refresh(); // re-layout all items (called automatically on resize)
115
- tl.initNewItems(); // pick up newly appended <li> elements
116
- tl.destroy(); // remove listeners and reset DOM classes
114
+ tl.refresh(); // re-layout all items (called automatically on resize)
115
+ tl.initNewItems(); // pick up manually appended <li> elements
116
+ tl.addItems(items); // create and append <li> from an array of item objects (or JSON string)
117
+ tl.destroy(); // remove listeners and reset DOM classes
118
+ ```
119
+
120
+ ### addItems — item schema
121
+
122
+ ```js
123
+ tl.addItems([
124
+ {
125
+ title: "Project kickoff", // <h3> heading
126
+ meta: "January 2024", // date / subtitle line
127
+ text: "Kicked off the roadmap.", // body paragraph
128
+ banner: "images/banner.jpg", // img.mo-banner (optional)
129
+ avatar: "images/avatar.jpg", // img.mo-avatar (optional)
130
+ icon: "images/icon.svg" // data-mo-icon on <li>, used by showCounterStyle:'image'
131
+ },
132
+ ]);
133
+
134
+ // A JSON string is also accepted:
135
+ tl.addItems('[{"title":"From JSON","meta":"Today","text":"Parsed automatically."}]');
117
136
  ```
118
137
 
119
138
  ---
@@ -157,6 +176,10 @@ No framework option needed. Wrap the `<ul>` inside a Bootstrap `.container`:
157
176
 
158
177
  ## Changelog
159
178
 
179
+ ### v2.4.0
180
+ - Added `addItems(items)` — creates and appends `<li>` elements from an array of item objects or a JSON string, then initializes them in one batch
181
+ - Badges and arrows now hidden in single-column mode (center-line elements have no meaning without a center line)
182
+
160
183
  ### v2.3.0
161
184
  - Added `showCounter` (opacity toggle) and `showCounterStyle` (`'counter'` | `'image'`) badge options
162
185
  - `data-mo-icon` attribute on `<li>` sets a custom icon in image mode; built-in flat SVG used as fallback
@@ -1,6 +1,6 @@
1
- "use strict";var b=Object.defineProperty;var E=(i,e,t)=>e in i?b(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t;var p=(i,e,t)=>E(i,typeof e!="symbol"?e+"":e,t);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});/*!
2
- * moTimeline v2.3.0
1
+ "use strict";var _=Object.defineProperty;var b=(o,e,t)=>e in o?_(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var p=(o,e,t)=>b(o,typeof e!="symbol"?e+"":e,t);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});/*!
2
+ * moTimeline v2.4.0
3
3
  * Responsive two-column timeline layout library
4
4
  * https://github.com/MattOpen/moTimeline
5
5
  * MIT License
6
- */const a=new WeakMap,w={columnCount:{xs:1,sm:2,md:2,lg:2},badgeShow:!1,arrowShow:!1,theme:!1,showCounter:!0,showCounterStyle:"counter"},I="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";function v(){const i=window.innerWidth;return i<600?"xs":i<992?"sm":i<1200?"md":"lg"}function y(i,e=100){let t;return(...s)=>{clearTimeout(t),t=setTimeout(()=>i(...s),e)}}function m(i){return i?{o:i.offsetTop,h:i.offsetHeight,gppu:i.offsetTop+i.offsetHeight}:{o:0,h:0,gppu:0}}function _(i,e){const t=[];let s=i.previousElementSibling;for(;s;)(!e||s.matches(e))&&t.push(s),s=s.previousElementSibling;return t}const l=class l{constructor(e,t={}){if(typeof e=="string"&&(e=document.querySelector(e)),!e)throw new Error("moTimeline: element not found");this.element=e,this.settings=Object.assign({},w,t),this.settings.columnCount=Object.assign({},w.columnCount,t.columnCount),this._resizeHandler=y(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(a.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});a.set(e,t),l.instances.add(this),e.classList.add("mo-timeline"),t.theme&&e.classList.add("mo-theme"),Array.from(e.children).length!==0&&(this._initItems(),this._initialized=!0,window.addEventListener("resize",this._resizeHandler))}refresh(){l.instances.forEach(e=>{const t=e.element,s=a.get(t);s&&(s.col=s.columnCount[v()],e._setDivider(),Array.from(t.children).forEach(o=>{e._setPostPosition(o)}))})}initNewItems(){this._initItems()}destroy(){window.removeEventListener("resize",this._resizeHandler),a.delete(this.element),l.instances.delete(this),this.element.classList.remove("mo-timeline","mo-theme","mo-twocol"),Array.from(this.element.children).forEach(e=>{e.classList.remove("mo-item","js-mo-item","mo-inverted","js-mo-inverted","mo-offset"),e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach(t=>t.remove())})}_getData(){return a.get(this.element)}_setDivider(){const e=this._getData();e&&(e.col=e.columnCount[v()],this.element.classList.toggle("mo-twocol",e.col>1))}_initItems(){const e=this.element,t=this._getData();if(!t)return;const s=t.lastItemIdx,o=Array.from(e.children),n=o.slice(s);n.length!==0&&(n.forEach((r,c)=>{r.id||(r.id="moT"+crypto.randomUUID()+"_"+(c+s)),r.classList.add("mo-item","js-mo-item")}),this._setDivider(),n.forEach((r,c)=>{t.badgeShow&&this._createBadge(r,c+s+1),t.arrowShow&&this._createArrow(r)}),t.lastItemIdx=o.length,a.set(e,t),this.refresh())}_setPostPosition(e){const t=this._getLeftOrRight(e);t&&(e.classList.toggle("mo-inverted",t.lr>0),e.classList.toggle("js-mo-inverted",t.lr>0),e.classList.toggle("mo-offset",t.badge_offset>0))}_getLeftOrRight(e){if(!e)return null;const t=this._getData();if(!t)return null;const s=t.col,o=_(e,".js-mo-inverted")[0]||null,n=_(e,".js-mo-item:not(.js-mo-inverted)")[0]||null,r=m(n),c=m(o),u=m(e);let h=0,f=0;if(s>1){r.gppu>u.o&&(h=1),c.gppu>r.gppu&&(h=0);const g=e.previousElementSibling;g&&Math.abs(u.o-m(g).o)<40&&(f=1)}return{lr:h,badge_offset:f}}_createBadge(e,t){const s=this._getData(),o=document.createElement("span");if(o.className="mo-badge js-mo-badge",s.showCounter||(o.style.opacity="0"),s.showCounterStyle==="image"){const n=document.createElement("img");n.className="mo-badge-icon",n.alt="",n.src=e.dataset.moIcon||I,o.appendChild(n)}else o.textContent=t;e.prepend(o)}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}};p(l,"instances",new Set);let d=l;exports.MoTimeline=d;exports.default=d;
6
+ */const c=new WeakMap,w={columnCount:{xs:1,sm:2,md:2,lg:2},badgeShow:!1,arrowShow:!1,theme:!1,showCounter:!0,showCounterStyle:"counter"},C="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";function v(){const o=window.innerWidth;return o<600?"xs":o<992?"sm":o<1200?"md":"lg"}function I(o,e=100){let t;return(...s)=>{clearTimeout(t),t=setTimeout(()=>o(...s),e)}}function m(o){return o?{o:o.offsetTop,h:o.offsetHeight,gppu:o.offsetTop+o.offsetHeight}:{o:0,h:0,gppu:0}}function E(o,e){const t=[];let s=o.previousElementSibling;for(;s;)(!e||s.matches(e))&&t.push(s),s=s.previousElementSibling;return t}const l=class l{constructor(e,t={}){if(typeof e=="string"&&(e=document.querySelector(e)),!e)throw new Error("moTimeline: element not found");this.element=e,this.settings=Object.assign({},w,t),this.settings.columnCount=Object.assign({},w.columnCount,t.columnCount),this._resizeHandler=I(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(c.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});c.set(e,t),l.instances.add(this),e.classList.add("mo-timeline"),t.theme&&e.classList.add("mo-theme"),Array.from(e.children).length!==0&&(this._initItems(),this._initialized=!0,window.addEventListener("resize",this._resizeHandler))}refresh(){l.instances.forEach(e=>{const t=e.element,s=c.get(t);s&&(s.col=s.columnCount[v()],e._setDivider(),Array.from(t.children).forEach(i=>{e._setPostPosition(i)}))})}initNewItems(){this._initItems()}addItems(e){typeof e=="string"&&(e=JSON.parse(e)),e.forEach(t=>this.element.appendChild(this._createItemElement(t))),this._initItems()}destroy(){window.removeEventListener("resize",this._resizeHandler),c.delete(this.element),l.instances.delete(this),this.element.classList.remove("mo-timeline","mo-theme","mo-twocol"),Array.from(this.element.children).forEach(e=>{e.classList.remove("mo-item","js-mo-item","mo-inverted","js-mo-inverted","mo-offset"),e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach(t=>t.remove())})}_getData(){return c.get(this.element)}_setDivider(){const e=this._getData();e&&(e.col=e.columnCount[v()],this.element.classList.toggle("mo-twocol",e.col>1))}_initItems(){const e=this.element,t=this._getData();if(!t)return;const s=t.lastItemIdx,i=Array.from(e.children),n=i.slice(s);n.length!==0&&(n.forEach((r,a)=>{r.id||(r.id="moT"+crypto.randomUUID()+"_"+(a+s)),r.classList.add("mo-item","js-mo-item")}),this._setDivider(),n.forEach((r,a)=>{t.badgeShow&&this._createBadge(r,a+s+1),t.arrowShow&&this._createArrow(r)}),t.lastItemIdx=i.length,c.set(e,t),this.refresh())}_setPostPosition(e){const t=this._getLeftOrRight(e);t&&(e.classList.toggle("mo-inverted",t.lr>0),e.classList.toggle("js-mo-inverted",t.lr>0),e.classList.toggle("mo-offset",t.badge_offset>0))}_getLeftOrRight(e){if(!e)return null;const t=this._getData();if(!t)return null;const s=t.col,i=E(e,".js-mo-inverted")[0]||null,n=E(e,".js-mo-item:not(.js-mo-inverted)")[0]||null,r=m(n),a=m(i),u=m(e);let h=0,f=0;if(s>1){r.gppu>u.o&&(h=1),a.gppu>r.gppu&&(h=0);const g=e.previousElementSibling;g&&Math.abs(u.o-m(g).o)<40&&(f=1)}return{lr:h,badge_offset:f}}_createBadge(e,t){const s=this._getData(),i=document.createElement("span");if(i.className="mo-badge js-mo-badge",s.showCounter||(i.style.opacity="0"),s.showCounterStyle==="image"){const n=document.createElement("img");n.className="mo-badge-icon",n.alt="",n.src=e.dataset.moIcon||C,i.appendChild(n)}else i.textContent=t;e.prepend(i)}_createItemElement(e){const t=document.createElement("li");e.icon&&(t.dataset.moIcon=e.icon);const s=document.createElement("div");if(s.className="mo-card",e.banner){const n=document.createElement("div");n.className="mo-card-image";const r=document.createElement("img");if(r.className="mo-banner",r.src=e.banner,r.alt="",n.appendChild(r),e.avatar){const a=document.createElement("img");a.className="mo-avatar",a.src=e.avatar,a.alt="",n.appendChild(a)}s.appendChild(n)}const i=document.createElement("div");if(i.className="mo-card-body",e.title){const n=document.createElement("h3");n.textContent=e.title,i.appendChild(n)}if(e.meta){const n=document.createElement("p");n.className="mo-meta",n.textContent=e.meta,i.appendChild(n)}if(e.text){const n=document.createElement("p");n.textContent=e.text,i.appendChild(n)}return s.appendChild(i),t.appendChild(s),t}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}};p(l,"instances",new Set);let d=l;exports.MoTimeline=d;exports.default=d;
@@ -1,3 +1,3 @@
1
1
  /*!
2
2
  * moTimeline v2.3.0 — CSS
3
- */:root{--mo-line-color: #dde1e7;--mo-badge-bg: #4f46e5;--mo-badge-color: #fff;--mo-badge-size: 26px;--mo-badge-font-size: 12px;--mo-arrow-color: #dde1e7}.mo-timeline{display:block;list-style:none;margin:0;padding:0;position:relative;width:100%}.mo-timeline:after{content:"";display:table;clear:both}.mo-timeline.mo-twocol:before{background-color:var(--mo-line-color);bottom:0;content:"";left:50%;margin-left:-1.5px;position:absolute;top:0;width:3px;z-index:0}.mo-timeline>.mo-item{box-sizing:border-box;display:block;float:left;position:relative;width:50%}.mo-timeline:not(.mo-twocol)>.mo-item{float:none;width:100%}.mo-timeline>.mo-item.mo-inverted{float:right}.mo-badge{align-items:center;background:var(--mo-badge-bg);border-radius:50%;color:var(--mo-badge-color);display:flex;font-size:var(--mo-badge-font-size);font-weight:700;height:var(--mo-badge-size);justify-content:center;min-width:var(--mo-badge-size);overflow:hidden;position:absolute;top:18px;z-index:2}.mo-badge .mo-badge-icon{border-radius:50%;height:100%;object-fit:cover;width:100%}.mo-timeline.mo-twocol>.mo-item:not(.mo-inverted) .mo-badge{left:auto;right:calc(var(--mo-badge-size) / -2)}.mo-timeline.mo-twocol>.mo-item.mo-inverted .mo-badge{left:calc(var(--mo-badge-size) / -2);right:auto}.mo-timeline.mo-twocol>.mo-item.mo-offset .mo-badge{top:calc(18px + var(--mo-badge-size) + 10px)}.mo-timeline.mo-twocol>.mo-item.mo-offset .mo-arrow{top:calc(26px + var(--mo-badge-size) + 10px)}.mo-timeline:not(.mo-twocol)>.mo-item .mo-badge{right:12px;left:auto;top:12px}.mo-arrow{border:8px solid transparent;display:block;height:0;position:absolute;top:26px;width:0;z-index:1}.mo-timeline.mo-twocol>.mo-item:not(.mo-inverted) .mo-arrow{border-left:8px solid var(--mo-arrow-color);border-right:none;left:auto;right:0}.mo-timeline.mo-twocol>.mo-item.mo-inverted .mo-arrow{border-right:8px solid var(--mo-arrow-color);border-left:none;left:0;right:auto}.mo-timeline:not(.mo-twocol)>.mo-item .mo-arrow{display:none}.mo-theme>.mo-item .mo-card{background:#fff;border-radius:8px;box-shadow:0 2px 14px #0000001a;margin:.5rem 1.25rem .5rem .5rem;overflow:hidden;position:relative}.mo-theme>.mo-item.mo-inverted .mo-card{margin:.5rem .5rem .5rem 1.25rem}.mo-theme>.mo-item .mo-banner{display:block;height:160px;object-fit:cover;width:100%}.mo-theme>.mo-item .mo-card-image{overflow:visible;position:relative}.mo-theme>.mo-item .mo-avatar{border:3px solid #fff;border-radius:50%;bottom:-22px;box-shadow:0 2px 8px #0000002e;height:50px;object-fit:cover;position:absolute;right:14px;width:50px;z-index:1}.mo-theme>.mo-item.mo-inverted .mo-avatar{left:14px;right:auto}.mo-theme>.mo-item .mo-card-body{padding:1.75rem 1rem 1rem}.mo-theme>.mo-item .mo-card-body h3{font-size:1rem;font-weight:700;margin:0 0 .3rem}.mo-theme>.mo-item .mo-card-body .mo-meta{color:#9ca3af;font-size:.75rem;margin-bottom:.5rem}.mo-theme>.mo-item .mo-card-body p{color:#6b7280;font-size:.875rem;line-height:1.55;margin:0}.mo-theme.mo-twocol>.mo-item:not(.mo-inverted) .mo-arrow{border-left-color:#e5e7eb;right:10px}.mo-theme.mo-twocol>.mo-item.mo-inverted .mo-arrow{border-right-color:#e5e7eb;left:10px}.mo-theme .mo-badge{background:#fff;border:2px solid var(--mo-line-color);box-shadow:0 2px 6px #0000001a;color:#374151}
3
+ */:root{--mo-line-color: #dde1e7;--mo-badge-bg: #4f46e5;--mo-badge-color: #fff;--mo-badge-size: 26px;--mo-badge-font-size: 12px;--mo-arrow-color: #dde1e7}.mo-timeline{display:block;list-style:none;margin:0;padding:0;position:relative;width:100%}.mo-timeline:after{content:"";display:table;clear:both}.mo-timeline.mo-twocol:before{background-color:var(--mo-line-color);bottom:0;content:"";left:50%;margin-left:-1.5px;position:absolute;top:0;width:3px;z-index:0}.mo-timeline>.mo-item{box-sizing:border-box;display:block;float:left;position:relative;width:50%}.mo-timeline:not(.mo-twocol)>.mo-item{float:none;width:100%}.mo-timeline>.mo-item.mo-inverted{float:right}.mo-badge{align-items:center;background:var(--mo-badge-bg);border-radius:50%;color:var(--mo-badge-color);display:flex;font-size:var(--mo-badge-font-size);font-weight:700;height:var(--mo-badge-size);justify-content:center;min-width:var(--mo-badge-size);overflow:hidden;position:absolute;top:18px;z-index:2}.mo-badge .mo-badge-icon{border-radius:50%;height:100%;object-fit:cover;width:100%}.mo-timeline.mo-twocol>.mo-item:not(.mo-inverted) .mo-badge{left:auto;right:calc(var(--mo-badge-size) / -2)}.mo-timeline.mo-twocol>.mo-item.mo-inverted .mo-badge{left:calc(var(--mo-badge-size) / -2);right:auto}.mo-timeline.mo-twocol>.mo-item.mo-offset .mo-badge{top:calc(18px + var(--mo-badge-size) + 10px)}.mo-timeline.mo-twocol>.mo-item.mo-offset .mo-arrow{top:calc(26px + var(--mo-badge-size) + 10px)}.mo-timeline:not(.mo-twocol)>.mo-item .mo-badge{display:none}.mo-arrow{border:8px solid transparent;display:block;height:0;position:absolute;top:26px;width:0;z-index:1}.mo-timeline.mo-twocol>.mo-item:not(.mo-inverted) .mo-arrow{border-left:8px solid var(--mo-arrow-color);border-right:none;left:auto;right:0}.mo-timeline.mo-twocol>.mo-item.mo-inverted .mo-arrow{border-right:8px solid var(--mo-arrow-color);border-left:none;left:0;right:auto}.mo-timeline:not(.mo-twocol)>.mo-item .mo-arrow{display:none}.mo-theme>.mo-item .mo-card{background:#fff;border-radius:8px;box-shadow:0 2px 14px #0000001a;margin:.5rem 1.25rem .5rem .5rem;overflow:hidden;position:relative}.mo-theme>.mo-item.mo-inverted .mo-card{margin:.5rem .5rem .5rem 1.25rem}.mo-theme>.mo-item .mo-banner{display:block;height:160px;object-fit:cover;width:100%}.mo-theme>.mo-item .mo-card-image{overflow:visible;position:relative}.mo-theme>.mo-item .mo-avatar{border:3px solid #fff;border-radius:50%;bottom:-22px;box-shadow:0 2px 8px #0000002e;height:50px;object-fit:cover;position:absolute;right:14px;width:50px;z-index:1}.mo-theme>.mo-item.mo-inverted .mo-avatar{left:14px;right:auto}.mo-theme>.mo-item .mo-card-body{padding:1.75rem 1rem 1rem}.mo-theme>.mo-item .mo-card-body h3{font-size:1rem;font-weight:700;margin:0 0 .3rem}.mo-theme>.mo-item .mo-card-body .mo-meta{color:#9ca3af;font-size:.75rem;margin-bottom:.5rem}.mo-theme>.mo-item .mo-card-body p{color:#6b7280;font-size:.875rem;line-height:1.55;margin:0}.mo-theme.mo-twocol>.mo-item:not(.mo-inverted) .mo-arrow{border-left-color:#e5e7eb;right:10px}.mo-theme.mo-twocol>.mo-item.mo-inverted .mo-arrow{border-right-color:#e5e7eb;left:10px}.mo-theme .mo-badge{background:#fff;border:2px solid var(--mo-line-color);box-shadow:0 2px 6px #0000001a;color:#374151}
@@ -1,13 +1,13 @@
1
- var b = Object.defineProperty;
2
- var E = (i, t, e) => t in i ? b(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
3
- var g = (i, t, e) => E(i, typeof t != "symbol" ? t + "" : t, e);
1
+ var _ = Object.defineProperty;
2
+ var C = (o, e, t) => e in o ? _(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t;
3
+ var g = (o, e, t) => C(o, typeof e != "symbol" ? e + "" : e, t);
4
4
  /*!
5
- * moTimeline v2.3.0
5
+ * moTimeline v2.4.0
6
6
  * Responsive two-column timeline layout library
7
7
  * https://github.com/MattOpen/moTimeline
8
8
  * MIT License
9
9
  */
10
- const a = /* @__PURE__ */ new WeakMap(), p = {
10
+ const c = /* @__PURE__ */ new WeakMap(), p = {
11
11
  columnCount: { xs: 1, sm: 2, md: 2, lg: 2 },
12
12
  badgeShow: !1,
13
13
  arrowShow: !1,
@@ -15,113 +15,154 @@ const a = /* @__PURE__ */ new WeakMap(), p = {
15
15
  showCounter: !0,
16
16
  showCounterStyle: "counter"
17
17
  // 'counter' | 'image'
18
- }, I = "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";
18
+ }, b = "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";
19
19
  function w() {
20
- const i = window.innerWidth;
21
- return i < 600 ? "xs" : i < 992 ? "sm" : i < 1200 ? "md" : "lg";
20
+ const o = window.innerWidth;
21
+ return o < 600 ? "xs" : o < 992 ? "sm" : o < 1200 ? "md" : "lg";
22
22
  }
23
- function L(i, t = 100) {
24
- let e;
23
+ function I(o, e = 100) {
24
+ let t;
25
25
  return (...s) => {
26
- clearTimeout(e), e = setTimeout(() => i(...s), t);
26
+ clearTimeout(t), t = setTimeout(() => o(...s), e);
27
27
  };
28
28
  }
29
- function m(i) {
30
- return i ? {
31
- o: i.offsetTop,
32
- h: i.offsetHeight,
33
- gppu: i.offsetTop + i.offsetHeight
29
+ function m(o) {
30
+ return o ? {
31
+ o: o.offsetTop,
32
+ h: o.offsetHeight,
33
+ gppu: o.offsetTop + o.offsetHeight
34
34
  } : { o: 0, h: 0, gppu: 0 };
35
35
  }
36
- function v(i, t) {
37
- const e = [];
38
- let s = i.previousElementSibling;
36
+ function v(o, e) {
37
+ const t = [];
38
+ let s = o.previousElementSibling;
39
39
  for (; s; )
40
- (!t || s.matches(t)) && e.push(s), s = s.previousElementSibling;
41
- return e;
40
+ (!e || s.matches(e)) && t.push(s), s = s.previousElementSibling;
41
+ return t;
42
42
  }
43
- const c = class c {
44
- constructor(t, e = {}) {
45
- if (typeof t == "string" && (t = document.querySelector(t)), !t) throw new Error("moTimeline: element not found");
46
- this.element = t, this.settings = Object.assign({}, p, e), this.settings.columnCount = Object.assign({}, p.columnCount, e.columnCount), this._resizeHandler = L(() => this.refresh(), 100), this._initialized = !1, this.init();
43
+ const l = class l {
44
+ constructor(e, t = {}) {
45
+ if (typeof e == "string" && (e = document.querySelector(e)), !e) throw new Error("moTimeline: element not found");
46
+ this.element = e, this.settings = Object.assign({}, p, t), this.settings.columnCount = Object.assign({}, p.columnCount, t.columnCount), this._resizeHandler = I(() => this.refresh(), 100), this._initialized = !1, this.init();
47
47
  }
48
48
  init() {
49
- const t = this.element;
50
- if (a.has(t)) {
49
+ const e = this.element;
50
+ if (c.has(e)) {
51
51
  this.refresh();
52
52
  return;
53
53
  }
54
- const e = Object.assign({}, this.settings, { lastItemIdx: 0 });
55
- a.set(t, e), c.instances.add(this), t.classList.add("mo-timeline"), e.theme && t.classList.add("mo-theme"), Array.from(t.children).length !== 0 && (this._initItems(), this._initialized = !0, window.addEventListener("resize", this._resizeHandler));
54
+ const t = Object.assign({}, this.settings, { lastItemIdx: 0 });
55
+ c.set(e, t), l.instances.add(this), e.classList.add("mo-timeline"), t.theme && e.classList.add("mo-theme"), Array.from(e.children).length !== 0 && (this._initItems(), this._initialized = !0, window.addEventListener("resize", this._resizeHandler));
56
56
  }
57
57
  refresh() {
58
- c.instances.forEach((t) => {
59
- const e = t.element, s = a.get(e);
60
- s && (s.col = s.columnCount[w()], t._setDivider(), Array.from(e.children).forEach((o) => {
61
- t._setPostPosition(o);
58
+ l.instances.forEach((e) => {
59
+ const t = e.element, s = c.get(t);
60
+ s && (s.col = s.columnCount[w()], e._setDivider(), Array.from(t.children).forEach((i) => {
61
+ e._setPostPosition(i);
62
62
  }));
63
63
  });
64
64
  }
65
65
  initNewItems() {
66
66
  this._initItems();
67
67
  }
68
+ /**
69
+ * Create <li> elements from an array of item objects (or a JSON string) and
70
+ * append them to the timeline, then initialize them in one batch.
71
+ *
72
+ * Item shape:
73
+ * { title, meta, text, banner, avatar, icon }
74
+ * — banner / avatar / icon are all optional
75
+ * — icon sets data-mo-icon on the <li> for showCounterStyle:'image'
76
+ */
77
+ addItems(e) {
78
+ typeof e == "string" && (e = JSON.parse(e)), e.forEach((t) => this.element.appendChild(this._createItemElement(t))), this._initItems();
79
+ }
68
80
  destroy() {
69
- window.removeEventListener("resize", this._resizeHandler), a.delete(this.element), c.instances.delete(this), this.element.classList.remove("mo-timeline", "mo-theme", "mo-twocol"), Array.from(this.element.children).forEach((t) => {
70
- t.classList.remove("mo-item", "js-mo-item", "mo-inverted", "js-mo-inverted", "mo-offset"), t.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach((e) => e.remove());
81
+ window.removeEventListener("resize", this._resizeHandler), c.delete(this.element), l.instances.delete(this), this.element.classList.remove("mo-timeline", "mo-theme", "mo-twocol"), Array.from(this.element.children).forEach((e) => {
82
+ e.classList.remove("mo-item", "js-mo-item", "mo-inverted", "js-mo-inverted", "mo-offset"), e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach((t) => t.remove());
71
83
  });
72
84
  }
73
85
  // ─── Private ────────────────────────────────────────────────────────────────
74
86
  _getData() {
75
- return a.get(this.element);
87
+ return c.get(this.element);
76
88
  }
77
89
  _setDivider() {
78
- const t = this._getData();
79
- t && (t.col = t.columnCount[w()], this.element.classList.toggle("mo-twocol", t.col > 1));
90
+ const e = this._getData();
91
+ e && (e.col = e.columnCount[w()], this.element.classList.toggle("mo-twocol", e.col > 1));
80
92
  }
81
93
  _initItems() {
82
- const t = this.element, e = this._getData();
83
- if (!e) return;
84
- const s = e.lastItemIdx, o = Array.from(t.children), n = o.slice(s);
85
- n.length !== 0 && (n.forEach((r, l) => {
86
- r.id || (r.id = "moT" + crypto.randomUUID() + "_" + (l + s)), r.classList.add("mo-item", "js-mo-item");
87
- }), this._setDivider(), n.forEach((r, l) => {
88
- e.badgeShow && this._createBadge(r, l + s + 1), e.arrowShow && this._createArrow(r);
89
- }), e.lastItemIdx = o.length, a.set(t, e), this.refresh());
94
+ const e = this.element, t = this._getData();
95
+ if (!t) return;
96
+ const s = t.lastItemIdx, i = Array.from(e.children), n = i.slice(s);
97
+ n.length !== 0 && (n.forEach((r, a) => {
98
+ r.id || (r.id = "moT" + crypto.randomUUID() + "_" + (a + s)), r.classList.add("mo-item", "js-mo-item");
99
+ }), this._setDivider(), n.forEach((r, a) => {
100
+ t.badgeShow && this._createBadge(r, a + s + 1), t.arrowShow && this._createArrow(r);
101
+ }), t.lastItemIdx = i.length, c.set(e, t), this.refresh());
90
102
  }
91
- _setPostPosition(t) {
92
- const e = this._getLeftOrRight(t);
93
- e && (t.classList.toggle("mo-inverted", e.lr > 0), t.classList.toggle("js-mo-inverted", e.lr > 0), t.classList.toggle("mo-offset", e.badge_offset > 0));
103
+ _setPostPosition(e) {
104
+ const t = this._getLeftOrRight(e);
105
+ t && (e.classList.toggle("mo-inverted", t.lr > 0), e.classList.toggle("js-mo-inverted", t.lr > 0), e.classList.toggle("mo-offset", t.badge_offset > 0));
94
106
  }
95
- _getLeftOrRight(t) {
96
- if (!t) return null;
97
- const e = this._getData();
107
+ _getLeftOrRight(e) {
98
108
  if (!e) return null;
99
- const s = e.col, o = v(t, ".js-mo-inverted")[0] || null, n = v(t, ".js-mo-item:not(.js-mo-inverted)")[0] || null, r = m(n), l = m(o), d = m(t);
100
- let h = 0, f = 0;
109
+ const t = this._getData();
110
+ if (!t) return null;
111
+ const s = t.col, i = v(e, ".js-mo-inverted")[0] || null, n = v(e, ".js-mo-item:not(.js-mo-inverted)")[0] || null, r = m(n), a = m(i), h = m(e);
112
+ let d = 0, f = 0;
101
113
  if (s > 1) {
102
- r.gppu > d.o && (h = 1), l.gppu > r.gppu && (h = 0);
103
- const u = t.previousElementSibling;
104
- u && Math.abs(d.o - m(u).o) < 40 && (f = 1);
114
+ r.gppu > h.o && (d = 1), a.gppu > r.gppu && (d = 0);
115
+ const u = e.previousElementSibling;
116
+ u && Math.abs(h.o - m(u).o) < 40 && (f = 1);
105
117
  }
106
- return { lr: h, badge_offset: f };
118
+ return { lr: d, badge_offset: f };
107
119
  }
108
- _createBadge(t, e) {
109
- const s = this._getData(), o = document.createElement("span");
110
- if (o.className = "mo-badge js-mo-badge", s.showCounter || (o.style.opacity = "0"), s.showCounterStyle === "image") {
120
+ _createBadge(e, t) {
121
+ const s = this._getData(), i = document.createElement("span");
122
+ if (i.className = "mo-badge js-mo-badge", s.showCounter || (i.style.opacity = "0"), s.showCounterStyle === "image") {
111
123
  const n = document.createElement("img");
112
- n.className = "mo-badge-icon", n.alt = "", n.src = t.dataset.moIcon || I, o.appendChild(n);
124
+ n.className = "mo-badge-icon", n.alt = "", n.src = e.dataset.moIcon || b, i.appendChild(n);
113
125
  } else
114
- o.textContent = e;
115
- t.prepend(o);
126
+ i.textContent = t;
127
+ e.prepend(i);
128
+ }
129
+ _createItemElement(e) {
130
+ const t = document.createElement("li");
131
+ e.icon && (t.dataset.moIcon = e.icon);
132
+ const s = document.createElement("div");
133
+ if (s.className = "mo-card", e.banner) {
134
+ const n = document.createElement("div");
135
+ n.className = "mo-card-image";
136
+ const r = document.createElement("img");
137
+ if (r.className = "mo-banner", r.src = e.banner, r.alt = "", n.appendChild(r), e.avatar) {
138
+ const a = document.createElement("img");
139
+ a.className = "mo-avatar", a.src = e.avatar, a.alt = "", n.appendChild(a);
140
+ }
141
+ s.appendChild(n);
142
+ }
143
+ const i = document.createElement("div");
144
+ if (i.className = "mo-card-body", e.title) {
145
+ const n = document.createElement("h3");
146
+ n.textContent = e.title, i.appendChild(n);
147
+ }
148
+ if (e.meta) {
149
+ const n = document.createElement("p");
150
+ n.className = "mo-meta", n.textContent = e.meta, i.appendChild(n);
151
+ }
152
+ if (e.text) {
153
+ const n = document.createElement("p");
154
+ n.textContent = e.text, i.appendChild(n);
155
+ }
156
+ return s.appendChild(i), t.appendChild(s), t;
116
157
  }
117
- _createArrow(t) {
118
- const e = document.createElement("span");
119
- e.className = "mo-arrow js-mo-arrow", t.prepend(e);
158
+ _createArrow(e) {
159
+ const t = document.createElement("span");
160
+ t.className = "mo-arrow js-mo-arrow", e.prepend(t);
120
161
  }
121
162
  };
122
- g(c, "instances", /* @__PURE__ */ new Set());
123
- let _ = c;
163
+ g(l, "instances", /* @__PURE__ */ new Set());
164
+ let E = l;
124
165
  export {
125
- _ as MoTimeline,
126
- _ as default
166
+ E as MoTimeline,
167
+ E as default
127
168
  };
@@ -1,6 +1,6 @@
1
- (function(n,i){typeof exports=="object"&&typeof module<"u"?i(exports):typeof define=="function"&&define.amd?define(["exports"],i):(n=typeof globalThis<"u"?globalThis:n||self,i(n.MoTimeline={}))})(this,function(n){"use strict";var I=Object.defineProperty;var j=(n,i,c)=>i in n?I(n,i,{enumerable:!0,configurable:!0,writable:!0,value:c}):n[i]=c;var b=(n,i,c)=>j(n,typeof i!="symbol"?i+"":i,c);/*!
2
- * moTimeline v2.3.0
1
+ (function(a,o){typeof exports=="object"&&typeof module<"u"?o(exports):typeof define=="function"&&define.amd?define(["exports"],o):(a=typeof globalThis<"u"?globalThis:a||self,o(a.MoTimeline={}))})(this,function(a){"use strict";var I=Object.defineProperty;var y=(a,o,m)=>o in a?I(a,o,{enumerable:!0,configurable:!0,writable:!0,value:m}):a[o]=m;var _=(a,o,m)=>y(a,typeof o!="symbol"?o+"":o,m);/*!
2
+ * moTimeline v2.4.0
3
3
  * Responsive two-column timeline layout library
4
4
  * https://github.com/MattOpen/moTimeline
5
5
  * MIT License
6
- */const i=new WeakMap,c={columnCount:{xs:1,sm:2,md:2,lg:2},badgeShow:!1,arrowShow:!1,theme:!1,showCounter:!0,showCounterStyle:"counter"},y="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";function g(){const o=window.innerWidth;return o<600?"xs":o<992?"sm":o<1200?"md":"lg"}function E(o,e=100){let t;return(...s)=>{clearTimeout(t),t=setTimeout(()=>o(...s),e)}}function f(o){return o?{o:o.offsetTop,h:o.offsetHeight,gppu:o.offsetTop+o.offsetHeight}:{o:0,h:0,gppu:0}}function p(o,e){const t=[];let s=o.previousElementSibling;for(;s;)(!e||s.matches(e))&&t.push(s),s=s.previousElementSibling;return t}const m=class m{constructor(e,t={}){if(typeof e=="string"&&(e=document.querySelector(e)),!e)throw new Error("moTimeline: element not found");this.element=e,this.settings=Object.assign({},c,t),this.settings.columnCount=Object.assign({},c.columnCount,t.columnCount),this._resizeHandler=E(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(i.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});i.set(e,t),m.instances.add(this),e.classList.add("mo-timeline"),t.theme&&e.classList.add("mo-theme"),Array.from(e.children).length!==0&&(this._initItems(),this._initialized=!0,window.addEventListener("resize",this._resizeHandler))}refresh(){m.instances.forEach(e=>{const t=e.element,s=i.get(t);s&&(s.col=s.columnCount[g()],e._setDivider(),Array.from(t.children).forEach(r=>{e._setPostPosition(r)}))})}initNewItems(){this._initItems()}destroy(){window.removeEventListener("resize",this._resizeHandler),i.delete(this.element),m.instances.delete(this),this.element.classList.remove("mo-timeline","mo-theme","mo-twocol"),Array.from(this.element.children).forEach(e=>{e.classList.remove("mo-item","js-mo-item","mo-inverted","js-mo-inverted","mo-offset"),e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach(t=>t.remove())})}_getData(){return i.get(this.element)}_setDivider(){const e=this._getData();e&&(e.col=e.columnCount[g()],this.element.classList.toggle("mo-twocol",e.col>1))}_initItems(){const e=this.element,t=this._getData();if(!t)return;const s=t.lastItemIdx,r=Array.from(e.children),a=r.slice(s);a.length!==0&&(a.forEach((l,d)=>{l.id||(l.id="moT"+crypto.randomUUID()+"_"+(d+s)),l.classList.add("mo-item","js-mo-item")}),this._setDivider(),a.forEach((l,d)=>{t.badgeShow&&this._createBadge(l,d+s+1),t.arrowShow&&this._createArrow(l)}),t.lastItemIdx=r.length,i.set(e,t),this.refresh())}_setPostPosition(e){const t=this._getLeftOrRight(e);t&&(e.classList.toggle("mo-inverted",t.lr>0),e.classList.toggle("js-mo-inverted",t.lr>0),e.classList.toggle("mo-offset",t.badge_offset>0))}_getLeftOrRight(e){if(!e)return null;const t=this._getData();if(!t)return null;const s=t.col,r=p(e,".js-mo-inverted")[0]||null,a=p(e,".js-mo-item:not(.js-mo-inverted)")[0]||null,l=f(a),d=f(r),w=f(e);let u=0,v=0;if(s>1){l.gppu>w.o&&(u=1),d.gppu>l.gppu&&(u=0);const _=e.previousElementSibling;_&&Math.abs(w.o-f(_).o)<40&&(v=1)}return{lr:u,badge_offset:v}}_createBadge(e,t){const s=this._getData(),r=document.createElement("span");if(r.className="mo-badge js-mo-badge",s.showCounter||(r.style.opacity="0"),s.showCounterStyle==="image"){const a=document.createElement("img");a.className="mo-badge-icon",a.alt="",a.src=e.dataset.moIcon||y,r.appendChild(a)}else r.textContent=t;e.prepend(r)}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}};b(m,"instances",new Set);let h=m;n.MoTimeline=h,n.default=h,Object.defineProperties(n,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
6
+ */const o=new WeakMap,m={columnCount:{xs:1,sm:2,md:2,lg:2},badgeShow:!1,arrowShow:!1,theme:!1,showCounter:!0,showCounterStyle:"counter"},b="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";function g(){const c=window.innerWidth;return c<600?"xs":c<992?"sm":c<1200?"md":"lg"}function C(c,e=100){let t;return(...n)=>{clearTimeout(t),t=setTimeout(()=>c(...n),e)}}function h(c){return c?{o:c.offsetTop,h:c.offsetHeight,gppu:c.offsetTop+c.offsetHeight}:{o:0,h:0,gppu:0}}function p(c,e){const t=[];let n=c.previousElementSibling;for(;n;)(!e||n.matches(e))&&t.push(n),n=n.previousElementSibling;return t}const d=class d{constructor(e,t={}){if(typeof e=="string"&&(e=document.querySelector(e)),!e)throw new Error("moTimeline: element not found");this.element=e,this.settings=Object.assign({},m,t),this.settings.columnCount=Object.assign({},m.columnCount,t.columnCount),this._resizeHandler=C(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(o.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});o.set(e,t),d.instances.add(this),e.classList.add("mo-timeline"),t.theme&&e.classList.add("mo-theme"),Array.from(e.children).length!==0&&(this._initItems(),this._initialized=!0,window.addEventListener("resize",this._resizeHandler))}refresh(){d.instances.forEach(e=>{const t=e.element,n=o.get(t);n&&(n.col=n.columnCount[g()],e._setDivider(),Array.from(t.children).forEach(i=>{e._setPostPosition(i)}))})}initNewItems(){this._initItems()}addItems(e){typeof e=="string"&&(e=JSON.parse(e)),e.forEach(t=>this.element.appendChild(this._createItemElement(t))),this._initItems()}destroy(){window.removeEventListener("resize",this._resizeHandler),o.delete(this.element),d.instances.delete(this),this.element.classList.remove("mo-timeline","mo-theme","mo-twocol"),Array.from(this.element.children).forEach(e=>{e.classList.remove("mo-item","js-mo-item","mo-inverted","js-mo-inverted","mo-offset"),e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach(t=>t.remove())})}_getData(){return o.get(this.element)}_setDivider(){const e=this._getData();e&&(e.col=e.columnCount[g()],this.element.classList.toggle("mo-twocol",e.col>1))}_initItems(){const e=this.element,t=this._getData();if(!t)return;const n=t.lastItemIdx,i=Array.from(e.children),s=i.slice(n);s.length!==0&&(s.forEach((r,l)=>{r.id||(r.id="moT"+crypto.randomUUID()+"_"+(l+n)),r.classList.add("mo-item","js-mo-item")}),this._setDivider(),s.forEach((r,l)=>{t.badgeShow&&this._createBadge(r,l+n+1),t.arrowShow&&this._createArrow(r)}),t.lastItemIdx=i.length,o.set(e,t),this.refresh())}_setPostPosition(e){const t=this._getLeftOrRight(e);t&&(e.classList.toggle("mo-inverted",t.lr>0),e.classList.toggle("js-mo-inverted",t.lr>0),e.classList.toggle("mo-offset",t.badge_offset>0))}_getLeftOrRight(e){if(!e)return null;const t=this._getData();if(!t)return null;const n=t.col,i=p(e,".js-mo-inverted")[0]||null,s=p(e,".js-mo-item:not(.js-mo-inverted)")[0]||null,r=h(s),l=h(i),w=h(e);let u=0,v=0;if(n>1){r.gppu>w.o&&(u=1),l.gppu>r.gppu&&(u=0);const E=e.previousElementSibling;E&&Math.abs(w.o-h(E).o)<40&&(v=1)}return{lr:u,badge_offset:v}}_createBadge(e,t){const n=this._getData(),i=document.createElement("span");if(i.className="mo-badge js-mo-badge",n.showCounter||(i.style.opacity="0"),n.showCounterStyle==="image"){const s=document.createElement("img");s.className="mo-badge-icon",s.alt="",s.src=e.dataset.moIcon||b,i.appendChild(s)}else i.textContent=t;e.prepend(i)}_createItemElement(e){const t=document.createElement("li");e.icon&&(t.dataset.moIcon=e.icon);const n=document.createElement("div");if(n.className="mo-card",e.banner){const s=document.createElement("div");s.className="mo-card-image";const r=document.createElement("img");if(r.className="mo-banner",r.src=e.banner,r.alt="",s.appendChild(r),e.avatar){const l=document.createElement("img");l.className="mo-avatar",l.src=e.avatar,l.alt="",s.appendChild(l)}n.appendChild(s)}const i=document.createElement("div");if(i.className="mo-card-body",e.title){const s=document.createElement("h3");s.textContent=e.title,i.appendChild(s)}if(e.meta){const s=document.createElement("p");s.className="mo-meta",s.textContent=e.meta,i.appendChild(s)}if(e.text){const s=document.createElement("p");s.textContent=e.text,i.appendChild(s)}return n.appendChild(i),t.appendChild(n),t}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}};_(d,"instances",new Set);let f=d;a.MoTimeline=f,a.default=f,Object.defineProperties(a,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "motimeline",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Responsive two-column timeline layout library. Plain JavaScript, no dependencies.",
5
5
  "main": "./dist/moTimeline.cjs",
6
6
  "module": "./dist/moTimeline.js",
@@ -113,11 +113,9 @@
113
113
  top: calc(26px + var(--mo-badge-size) + 10px);
114
114
  }
115
115
 
116
- /* Single column: badge in top-right of item */
116
+ /* Single column: hide badge (center-line elements have no meaning without a center line) */
117
117
  .mo-timeline:not(.mo-twocol) > .mo-item .mo-badge {
118
- right: 12px;
119
- left: auto;
120
- top: 12px;
118
+ display: none;
121
119
  }
122
120
 
123
121
  /* ── Arrow — triangle pointing FROM card TOWARD center line ─── */
package/src/moTimeline.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * moTimeline v2.3.0
2
+ * moTimeline v2.4.0
3
3
  * Responsive two-column timeline layout library
4
4
  * https://github.com/MattOpen/moTimeline
5
5
  * MIT License
@@ -124,6 +124,21 @@ export class MoTimeline {
124
124
  this._initItems();
125
125
  }
126
126
 
127
+ /**
128
+ * Create <li> elements from an array of item objects (or a JSON string) and
129
+ * append them to the timeline, then initialize them in one batch.
130
+ *
131
+ * Item shape:
132
+ * { title, meta, text, banner, avatar, icon }
133
+ * — banner / avatar / icon are all optional
134
+ * — icon sets data-mo-icon on the <li> for showCounterStyle:'image'
135
+ */
136
+ addItems(items) {
137
+ if (typeof items === 'string') items = JSON.parse(items);
138
+ items.forEach((item) => this.element.appendChild(this._createItemElement(item)));
139
+ this._initItems();
140
+ }
141
+
127
142
  destroy() {
128
143
  window.removeEventListener('resize', this._resizeHandler);
129
144
  instanceData.delete(this.element);
@@ -248,6 +263,54 @@ export class MoTimeline {
248
263
  el.prepend(span);
249
264
  }
250
265
 
266
+ _createItemElement(item) {
267
+ const li = document.createElement('li');
268
+ if (item.icon) li.dataset.moIcon = item.icon;
269
+
270
+ const card = document.createElement('div');
271
+ card.className = 'mo-card';
272
+
273
+ if (item.banner) {
274
+ const wrap = document.createElement('div');
275
+ wrap.className = 'mo-card-image';
276
+ const banner = document.createElement('img');
277
+ banner.className = 'mo-banner';
278
+ banner.src = item.banner;
279
+ banner.alt = '';
280
+ wrap.appendChild(banner);
281
+ if (item.avatar) {
282
+ const avatar = document.createElement('img');
283
+ avatar.className = 'mo-avatar';
284
+ avatar.src = item.avatar;
285
+ avatar.alt = '';
286
+ wrap.appendChild(avatar);
287
+ }
288
+ card.appendChild(wrap);
289
+ }
290
+
291
+ const body = document.createElement('div');
292
+ body.className = 'mo-card-body';
293
+ if (item.title) {
294
+ const h = document.createElement('h3');
295
+ h.textContent = item.title;
296
+ body.appendChild(h);
297
+ }
298
+ if (item.meta) {
299
+ const m = document.createElement('p');
300
+ m.className = 'mo-meta';
301
+ m.textContent = item.meta;
302
+ body.appendChild(m);
303
+ }
304
+ if (item.text) {
305
+ const p = document.createElement('p');
306
+ p.textContent = item.text;
307
+ body.appendChild(p);
308
+ }
309
+ card.appendChild(body);
310
+ li.appendChild(card);
311
+ return li;
312
+ }
313
+
251
314
  _createArrow(el) {
252
315
  const span = document.createElement('span');
253
316
  span.className = 'mo-arrow js-mo-arrow';