@africode/core 5.0.6 → 5.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/components/breadcrumb.js +72 -0
  2. package/components/carousel.js +32 -0
  3. package/components/cart-drawer.js +28 -0
  4. package/components/code-block.js +20 -0
  5. package/components/contact-form.js +25 -0
  6. package/components/cookie-consent.js +23 -0
  7. package/components/cta-banner.js +38 -0
  8. package/components/dashboard-activity-list.js +103 -0
  9. package/components/dashboard-card.js +85 -0
  10. package/components/dashboard-metric.js +81 -0
  11. package/components/dashboard-shell.js +85 -0
  12. package/components/dashboard-topbar.js +84 -0
  13. package/components/faq-accordion.js +23 -0
  14. package/components/feature-grid.js +85 -0
  15. package/components/file-uploader.js +22 -0
  16. package/components/filter-bar.js +19 -0
  17. package/components/footer.js +113 -0
  18. package/components/gallery.js +22 -0
  19. package/components/index.js +42 -0
  20. package/components/newsletter-signup.js +24 -0
  21. package/components/pagination.js +31 -0
  22. package/components/pricing-card.js +100 -0
  23. package/components/product-card.js +41 -0
  24. package/components/search-box.js +24 -0
  25. package/components/simple-chart.js +22 -0
  26. package/components/stepper.js +28 -0
  27. package/components/team-grid.js +23 -0
  28. package/components/testimonial.js +94 -0
  29. package/components/ui-avatar.js +79 -0
  30. package/components/ui-chip.js +87 -0
  31. package/components/ui-popover.js +84 -0
  32. package/components/ui-progress-ring.js +60 -0
  33. package/components/ui-select.js +85 -0
  34. package/components/ui-stat.js +75 -0
  35. package/components/ui-table.js +69 -0
  36. package/components/ui-tabs.js +99 -0
  37. package/components/ui-tag.js +64 -0
  38. package/components/ui-textarea.js +84 -0
  39. package/components/ui-tooltip.js +66 -0
  40. package/components/video-player.js +22 -0
  41. package/dist/africode.js +1480 -549
  42. package/dist/africode.js.map +25 -4
  43. package/dist/build-info.json +3 -3
  44. package/dist/components.js +1506 -575
  45. package/dist/components.js.map +25 -4
  46. package/package.json +1 -1
@@ -0,0 +1,99 @@
1
+ /**
2
+ * AfriCode UI Tabs
3
+ *
4
+ * A simple tabbed interface for content panels.
5
+ * @module components/ui-tabs
6
+ */
7
+
8
+ import { AfriCodeComponent, registerComponent, html } from './base.js';
9
+
10
+ export class AfriUITabs extends AfriCodeComponent {
11
+ static get observedAttributes() {
12
+ return ['active'];
13
+ }
14
+
15
+ constructor() {
16
+ super();
17
+ this._active = this.getAttribute('active') || '0';
18
+ this.render();
19
+ }
20
+
21
+ connectedCallback() {
22
+ this._attachListeners();
23
+ }
24
+
25
+ attributeChangedCallback() {
26
+ this._active = this.getAttribute('active') || '0';
27
+ this.render();
28
+ this._attachListeners();
29
+ }
30
+
31
+ _attachListeners() {
32
+ const tabButtons = this.shadowRoot.querySelectorAll('[role="tab"]');
33
+ tabButtons.forEach((tab) => {
34
+ tab.addEventListener('click', () => {
35
+ const index = tab.getAttribute('data-index');
36
+ this.setAttribute('active', index);
37
+ });
38
+ });
39
+ }
40
+
41
+ render() {
42
+ const active = this._active;
43
+ const tabs = Array.from(this.children).filter((child) => child.tagName.toLowerCase() === 'ui-tab-panel');
44
+
45
+ this.shadowRoot.innerHTML = html`
46
+ <style>
47
+ :host { display: block; font-family: 'Inter', system-ui, sans-serif; }
48
+
49
+ .tab-list {
50
+ display: flex;
51
+ gap: 0.5rem;
52
+ border-bottom: 1px solid #e5e7eb;
53
+ margin-bottom: 1rem;
54
+ }
55
+ button {
56
+ all: unset;
57
+ cursor: pointer;
58
+ padding: 0.75rem 1rem;
59
+ border-radius: 999px;
60
+ color: #334155;
61
+ font-weight: 600;
62
+ }
63
+ button.active {
64
+ background: #2563eb;
65
+ color: #fff;
66
+ }
67
+ .panel { display: none; }
68
+ .panel.active { display: block; }
69
+ </style>
70
+ <div class="tab-list" role="tablist">
71
+ ${tabs.map((tab, index) => html`
72
+ <button
73
+ role="tab"
74
+ data-index="${index}"
75
+ class="${String(index) === String(active) ? 'active' : ''}"
76
+ aria-selected="${String(index) === String(active)}"
77
+ >
78
+ ${tab.getAttribute('label') || `Tab ${index + 1}`}
79
+ </button>
80
+ `).join('')}
81
+ </div>
82
+ ${tabs.map((tab, index) => html`
83
+ <div class="panel ${String(index) === String(active) ? 'active' : ''}" role="tabpanel">
84
+ ${tab.innerHTML}
85
+ </div>
86
+ `).join('')}
87
+ `;
88
+ }
89
+ }
90
+
91
+ export class AfriUITabPanel extends AfriCodeComponent {
92
+ render() {
93
+ this.shadowRoot.innerHTML = html`<slot></slot>`;
94
+ }
95
+ }
96
+
97
+ registerComponent('af-ui-tabs', AfriUITabs);
98
+ registerComponent('ui-tab-panel', AfriUITabPanel);
99
+ export default AfriUITabs;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * AfriCode UI Tag
3
+ *
4
+ * Simple inline tag for metadata, status, and category labels.
5
+ * @module components/ui-tag
6
+ */
7
+
8
+ import { AfriCodeComponent, registerComponent, html } from './base.js';
9
+
10
+ export class AfriUITag extends AfriCodeComponent {
11
+ static get observedAttributes() {
12
+ return ['variant', 'size'];
13
+ }
14
+
15
+ constructor() {
16
+ super();
17
+ this.render();
18
+ }
19
+
20
+ attributeChangedCallback() {
21
+ this.render();
22
+ }
23
+
24
+ render() {
25
+ const variant = this.getAttribute('variant') || 'secondary';
26
+ const size = this.getAttribute('size') || 'md';
27
+ const sizes = {
28
+ sm: '0.25rem 0.6rem',
29
+ md: '0.35rem 0.8rem',
30
+ lg: '0.5rem 1rem'
31
+ };
32
+
33
+ this.shadowRoot.innerHTML = html`
34
+ <style>
35
+ :host { display: inline-block; font-family: 'Inter', sans-serif; }
36
+
37
+ .tag {
38
+ display: inline-flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ gap: 0.35rem;
42
+ padding: ${sizes[size]};
43
+ border-radius: 999px;
44
+ font-size: ${size === 'sm' ? '0.75rem' : size === 'lg' ? '0.95rem' : '0.85rem'};
45
+ font-weight: 600;
46
+ color: #111827;
47
+ background: #f8fafc;
48
+ border: 1px solid rgba(15, 23, 42, 0.08);
49
+ }
50
+
51
+ .tag.primary { background: #dbeafe; color: #1e40af; }
52
+ .tag.success { background: #d1fae5; color: #14532d; }
53
+ .tag.warning { background: #fde68a; color: #92400e; }
54
+ .tag.danger { background: #fecaca; color: #991b1b; }
55
+ .tag.secondary { background: #f3f4f6; color: #1f2937; }
56
+ </style>
57
+
58
+ <span class="tag ${variant}"><slot></slot></span>
59
+ `;
60
+ }
61
+ }
62
+
63
+ registerComponent('af-ui-tag', AfriUITag);
64
+ export default AfriUITag;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * AfriCode UI Textarea
3
+ *
4
+ * Styled textarea component for forms and content entry.
5
+ * @module components/ui-textarea
6
+ */
7
+
8
+ import { AfriCodeComponent, registerComponent, html } from './base.js';
9
+
10
+ export class AfriUITextarea extends AfriCodeComponent {
11
+ static get observedAttributes() {
12
+ return ['label', 'placeholder', 'rows', 'disabled', 'error'];
13
+ }
14
+
15
+ constructor() {
16
+ super();
17
+ this.render();
18
+ }
19
+
20
+ connectedCallback() {
21
+ this._attachListeners();
22
+ this.loadStyles();
23
+ }
24
+
25
+ attributeChangedCallback() {
26
+ this.render();
27
+ this._attachListeners();
28
+ }
29
+
30
+ _attachListeners() {
31
+ const textarea = this.shadowRoot.querySelector('textarea');
32
+ if (!textarea) return;
33
+ textarea.addEventListener('input', () => {
34
+ this.emit('af-ui-textarea', { value: textarea.value });
35
+ });
36
+ }
37
+
38
+ render() {
39
+ const label = this.getAttribute('label') || '';
40
+ const placeholder = this.getAttribute('placeholder') || '';
41
+ const rows = this.getAttribute('rows') || '4';
42
+ const disabled = this.hasAttribute('disabled');
43
+ const error = this.getAttribute('error') || '';
44
+
45
+ this.shadowRoot.innerHTML = html`
46
+ <style>
47
+ :host { display: block; font-family: 'Inter', system-ui, sans-serif; }
48
+
49
+ .field { display: grid; gap: 0.5rem; }
50
+ label { font-size: 0.85rem; font-weight: 600; color: #111827; }
51
+ textarea {
52
+ width: 100%;
53
+ min-height: 120px;
54
+ border: 1px solid #d1d5db;
55
+ border-radius: 0.75rem;
56
+ padding: 1rem;
57
+ font-size: 0.95rem;
58
+ font-family: inherit;
59
+ color: #111827;
60
+ resize: vertical;
61
+ background: #fff;
62
+ transition: border-color 150ms ease, box-shadow 150ms ease;
63
+ }
64
+ textarea:focus {
65
+ border-color: #2563eb;
66
+ box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.12);
67
+ outline: none;
68
+ }
69
+ textarea:disabled { background: #f8fafc; cursor: not-allowed; }
70
+
71
+ .error { color: #dc2626; font-size: 0.8rem; min-height: 1rem; }
72
+ </style>
73
+
74
+ <div class="field">
75
+ ${label ? html`<label>${label}</label>` : ''}
76
+ <textarea rows="${rows}" placeholder="${placeholder}" ${disabled ? 'disabled' : ''}></textarea>
77
+ <div class="error">${error}</div>
78
+ </div>
79
+ `;
80
+ }
81
+ }
82
+
83
+ registerComponent('af-ui-textarea', AfriUITextarea);
84
+ export default AfriUITextarea;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * AfriCode UI Tooltip
3
+ *
4
+ * Lightweight tooltip component for inline help and hover hints.
5
+ * @module components/ui-tooltip
6
+ */
7
+
8
+ import { AfriCodeComponent, registerComponent, html } from './base.js';
9
+
10
+ export class AfriUITooltip extends AfriCodeComponent {
11
+ static get observedAttributes() {
12
+ return ['text', 'position'];
13
+ }
14
+
15
+ constructor() {
16
+ super();
17
+ this.render();
18
+ }
19
+
20
+ attributeChangedCallback() {
21
+ this.render();
22
+ }
23
+
24
+ render() {
25
+ const text = this.getAttribute('text') || '';
26
+ const position = this.getAttribute('position') || 'top';
27
+
28
+ this.shadowRoot.innerHTML = html`
29
+ <style>
30
+ :host { position: relative; display: inline-flex; }
31
+
32
+ .tooltip {
33
+ position: absolute;
34
+ white-space: nowrap;
35
+ padding: 0.55rem 0.75rem;
36
+ background: rgba(15, 23, 42, 0.95);
37
+ color: #fff;
38
+ border-radius: 0.65rem;
39
+ font-size: 0.75rem;
40
+ transform: translateY(-8px);
41
+ opacity: 0;
42
+ pointer-events: none;
43
+ transition: opacity 0.2s ease, transform 0.2s ease;
44
+ z-index: 100;
45
+ }
46
+ :host(:hover) .tooltip { opacity: 1; transform: translateY(0); }
47
+ .tooltip::after {
48
+ content: '';
49
+ position: absolute;
50
+ width: 0;
51
+ height: 0;
52
+ border-style: solid;
53
+ }
54
+ .tooltip.top { bottom: 100%; left: 50%; transform: translate(-50%, -8px); }
55
+ .tooltip.top::after { top: 100%; left: 50%; transform: translateX(-50%); border-width: 6px 6px 0 6px; border-color: rgba(15,23,42,0.95) transparent transparent transparent; }
56
+ .tooltip.bottom { top: 100%; left: 50%; transform: translate(-50%, 8px); }
57
+ .tooltip.bottom::after { bottom: 100%; left: 50%; transform: translateX(-50%); border-width: 0 6px 6px 6px; border-color: transparent transparent rgba(15,23,42,0.95) transparent; }
58
+ </style>
59
+ <slot></slot>
60
+ <div class="tooltip ${position}" role="tooltip">${text}</div>
61
+ `;
62
+ }
63
+ }
64
+
65
+ registerComponent('af-ui-tooltip', AfriUITooltip);
66
+ export default AfriUITooltip;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * AfriCode Video Player
3
+ *
4
+ * Lightweight video player wrapper.
5
+ */
6
+
7
+ import { AfriCodeComponent, registerComponent, html } from './base.js';
8
+
9
+ export class AfriVideoPlayer extends AfriCodeComponent {
10
+ static get observedAttributes(){return ['src','poster']}
11
+ constructor(){ super(); this.render(); }
12
+ attributeChangedCallback(){ this.render(); }
13
+ render(){ const src=this.getAttribute('src')||''; const poster=this.getAttribute('poster')||''; this.shadowRoot.innerHTML = html`
14
+ <style>
15
+ video{width:100%;border-radius:12px;background:#000}
16
+ </style>
17
+ <video controls src="${src}" poster="${poster}"></video>
18
+ ` }
19
+ }
20
+
21
+ registerComponent('af-video-player', AfriVideoPlayer);
22
+ export default AfriVideoPlayer;