@forcecalendar/interface 1.0.46 → 1.0.48

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forcecalendar/interface",
3
- "version": "1.0.46",
3
+ "version": "1.0.48",
4
4
  "type": "module",
5
5
  "description": "Official interface layer for forceCalendar Core - Enterprise calendar components",
6
6
  "main": "dist/force-calendar-interface.umd.js",
@@ -115,40 +115,16 @@ export class BaseViewRenderer {
115
115
  }
116
116
 
117
117
  /**
118
- * Get contrasting text color for a background color
119
- * Uses WCAG luminance formula
118
+ * Get contrasting text color for a background color.
119
+ * Delegates to StyleUtils.getContrastColor() as the single implementation.
120
120
  * @param {string} bgColor - Hex color string
121
- * @returns {string} 'black' or 'white'
121
+ * @returns {string} '#000000' or '#FFFFFF'
122
122
  */
123
123
  getContrastingTextColor(bgColor) {
124
- if (!bgColor || typeof bgColor !== 'string') return 'white';
125
-
126
- const color = bgColor.charAt(0) === '#' ? bgColor.substring(1) : bgColor;
127
-
128
- if (!/^[0-9A-Fa-f]{3}$|^[0-9A-Fa-f]{6}$/.test(color)) {
129
- return 'white';
130
- }
131
-
132
- const fullColor =
133
- color.length === 3 ? color[0] + color[0] + color[1] + color[1] + color[2] + color[2] : color;
134
-
135
- const r = parseInt(fullColor.substring(0, 2), 16);
136
- const g = parseInt(fullColor.substring(2, 4), 16);
137
- const b = parseInt(fullColor.substring(4, 6), 16);
138
-
139
- if (isNaN(r) || isNaN(g) || isNaN(b)) {
124
+ if (!bgColor || typeof bgColor !== 'string' || bgColor.charAt(0) !== '#') {
140
125
  return 'white';
141
126
  }
142
-
143
- const uicolors = [r / 255, g / 255, b / 255];
144
- const c = uicolors.map(col => {
145
- if (col <= 0.03928) {
146
- return col / 12.92;
147
- }
148
- return Math.pow((col + 0.055) / 1.055, 2.4);
149
- });
150
- const L = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
151
- return L > 0.179 ? 'black' : 'white';
127
+ return StyleUtils.getContrastColor(bgColor);
152
128
  }
153
129
 
154
130
  /**
@@ -158,7 +134,7 @@ export class BaseViewRenderer {
158
134
  renderNowIndicator() {
159
135
  const now = new Date();
160
136
  const minutes = now.getHours() * 60 + now.getMinutes();
161
- return `<div class="fc-now-indicator" style="position: absolute; left: 0; right: 0; top: ${minutes}px; height: 2px; background: #dc2626; z-index: 15; pointer-events: none;"></div>`;
137
+ return `<div class="fc-now-indicator" style="position: absolute; left: 0; right: 0; top: ${minutes}px; height: 2px; background: var(--fc-danger-color); z-index: 15; pointer-events: none;"></div>`;
162
138
  }
163
139
 
164
140
  /**
@@ -19,7 +19,7 @@ export class DayViewRenderer extends BaseViewRenderer {
19
19
  const viewData = this.stateManager.getViewData();
20
20
  if (!viewData) {
21
21
  this.container.innerHTML =
22
- '<div style="padding: 20px; text-align: center; color: #666;">No data available for day view.</div>';
22
+ '<div style="padding: 20px; text-align: center; color: var(--fc-text-secondary);">No data available for day view.</div>';
23
23
  return;
24
24
  }
25
25
 
@@ -37,14 +37,14 @@ export class DayViewRenderer extends BaseViewRenderer {
37
37
  const dayData = this._extractDayData(viewData, currentDate);
38
38
 
39
39
  if (!dayData) {
40
- return '<div style="padding: 20px; text-align: center; color: #666;">No data available for day view.</div>';
40
+ return '<div style="padding: 20px; text-align: center; color: var(--fc-text-secondary);">No data available for day view.</div>';
41
41
  }
42
42
 
43
43
  const { dayDate, dayName, isToday, allDayEvents, timedEvents } = dayData;
44
44
  const hours = Array.from({ length: 24 }, (_, i) => i);
45
45
 
46
46
  return `
47
- <div class="fc-day-view" style="display: flex; flex-direction: column; height: 100%; background: #fff; overflow: hidden;">
47
+ <div class="fc-day-view" style="display: flex; flex-direction: column; height: 100%; background: var(--fc-background); overflow: hidden;">
48
48
  ${this._renderHeader(dayDate, dayName, isToday)}
49
49
  ${this._renderAllDayRow(allDayEvents, dayDate)}
50
50
  ${this._renderTimeGrid(timedEvents, isToday, dayDate, hours)}
@@ -96,13 +96,13 @@ export class DayViewRenderer extends BaseViewRenderer {
96
96
 
97
97
  _renderHeader(dayDate, dayName, isToday) {
98
98
  return `
99
- <div class="fc-day-header" style="display: grid; grid-template-columns: 60px 1fr; border-bottom: 1px solid #e5e7eb; background: #f9fafb; flex-shrink: 0;">
100
- <div style="border-right: 1px solid #e5e7eb;"></div>
99
+ <div class="fc-day-header" style="display: grid; grid-template-columns: 60px 1fr; border-bottom: 1px solid var(--fc-border-color); background: var(--fc-background-alt); flex-shrink: 0;">
100
+ <div style="border-right: 1px solid var(--fc-border-color);"></div>
101
101
  <div style="padding: 16px 24px;">
102
- <div style="font-size: 12px; font-weight: 700; color: #6b7280; text-transform: uppercase; letter-spacing: 0.1em;">
102
+ <div style="font-size: 12px; font-weight: 700; color: var(--fc-text-light); text-transform: uppercase; letter-spacing: 0.1em;">
103
103
  ${dayName}
104
104
  </div>
105
- <div style="font-size: 24px; font-weight: 600; margin-top: 4px; ${isToday ? 'color: #dc2626;' : 'color: #111827;'}">
105
+ <div style="font-size: 24px; font-weight: 600; margin-top: 4px; ${isToday ? 'color: var(--fc-danger-color);' : 'color: var(--fc-text-color);'}">
106
106
  ${dayDate.getDate()}
107
107
  </div>
108
108
  </div>
@@ -112,8 +112,8 @@ export class DayViewRenderer extends BaseViewRenderer {
112
112
 
113
113
  _renderAllDayRow(allDayEvents, dayDate) {
114
114
  return `
115
- <div class="fc-all-day-row" style="display: grid; grid-template-columns: 60px 1fr; border-bottom: 1px solid #e5e7eb; background: #fafafa; min-height: 36px; flex-shrink: 0;">
116
- <div style="font-size: 9px; color: #6b7280; display: flex; align-items: center; justify-content: center; border-right: 1px solid #e5e7eb; text-transform: uppercase; font-weight: 700;">
115
+ <div class="fc-all-day-row" style="display: grid; grid-template-columns: 60px 1fr; border-bottom: 1px solid var(--fc-border-color); background: var(--fc-background-alt); min-height: 36px; flex-shrink: 0;">
116
+ <div style="font-size: 9px; color: var(--fc-text-light); display: flex; align-items: center; justify-content: center; border-right: 1px solid var(--fc-border-color); text-transform: uppercase; font-weight: 700;">
117
117
  All day
118
118
  </div>
119
119
  <div class="fc-all-day-cell" data-date="${dayDate.toISOString()}" style="padding: 6px 12px; display: flex; flex-wrap: wrap; gap: 4px;">
@@ -145,11 +145,11 @@ export class DayViewRenderer extends BaseViewRenderer {
145
145
 
146
146
  _renderTimeGutter(hours) {
147
147
  return `
148
- <div class="fc-time-gutter" style="border-right: 1px solid #e5e7eb; background: #fafafa;">
148
+ <div class="fc-time-gutter" style="border-right: 1px solid var(--fc-border-color); background: var(--fc-background-alt);">
149
149
  ${hours
150
150
  .map(
151
151
  h => `
152
- <div style="height: ${this.hourHeight}px; font-size: 11px; color: #6b7280; text-align: right; padding-right: 12px; font-weight: 500;">
152
+ <div style="height: ${this.hourHeight}px; font-size: 11px; color: var(--fc-text-light); text-align: right; padding-right: 12px; font-weight: 500;">
153
153
  ${h === 0 ? '' : this.formatHour(h)}
154
154
  </div>
155
155
  `
@@ -163,7 +163,7 @@ export class DayViewRenderer extends BaseViewRenderer {
163
163
  return `
164
164
  <div class="fc-day-column" data-date="${dayDate.toISOString()}" style="position: relative; cursor: pointer;">
165
165
  <!-- Hour grid lines -->
166
- ${hours.map(() => `<div style="height: ${this.hourHeight}px; border-bottom: 1px solid #f3f4f6;"></div>`).join('')}
166
+ ${hours.map(() => `<div style="height: ${this.hourHeight}px; border-bottom: 1px solid var(--fc-background-hover);"></div>`).join('')}
167
167
 
168
168
  <!-- Now indicator for today -->
169
169
  ${isToday ? this.renderNowIndicator() : ''}
@@ -18,7 +18,7 @@ export class MonthViewRenderer extends BaseViewRenderer {
18
18
  const viewData = this.stateManager.getViewData();
19
19
  if (!viewData || !viewData.weeks) {
20
20
  this.container.innerHTML =
21
- '<div style="padding: 20px; text-align: center; color: #666;">No data available for month view.</div>';
21
+ '<div style="padding: 20px; text-align: center; color: var(--fc-text-secondary);">No data available for month view.</div>';
22
22
  return;
23
23
  }
24
24
 
@@ -34,9 +34,9 @@ export class MonthViewRenderer extends BaseViewRenderer {
34
34
  const dayNames = this._getDayNames(weekStartsOn);
35
35
 
36
36
  let html = `
37
- <div class="fc-month-view" style="display: flex; flex-direction: column; height: 100%; min-height: 400px; background: #fff; border: 1px solid #e5e7eb;">
38
- <div class="fc-month-header" style="display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid #e5e7eb; background: #f9fafb;">
39
- ${dayNames.map(d => `<div class="fc-month-header-cell" style="padding: 12px 8px; text-align: center; font-size: 11px; font-weight: 600; color: #6b7280; text-transform: uppercase;">${d}</div>`).join('')}
37
+ <div class="fc-month-view" style="display: flex; flex-direction: column; height: 100%; min-height: 400px; background: var(--fc-background); border: 1px solid var(--fc-border-color);">
38
+ <div class="fc-month-header" style="display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid var(--fc-border-color); background: var(--fc-background-alt);">
39
+ ${dayNames.map(d => `<div class="fc-month-header-cell" style="padding: 12px 8px; text-align: center; font-size: 11px; font-weight: 600; color: var(--fc-text-light); text-transform: uppercase;">${d}</div>`).join('')}
40
40
  </div>
41
41
  <div class="fc-month-body" style="display: flex; flex-direction: column; flex: 1;">
42
42
  `;
@@ -75,10 +75,10 @@ export class MonthViewRenderer extends BaseViewRenderer {
75
75
  const isOtherMonth = !day.isCurrentMonth;
76
76
  const isToday = day.isToday;
77
77
 
78
- const dayBg = isOtherMonth ? '#f3f4f6' : '#fff';
79
- const dayNumColor = isOtherMonth ? '#9ca3af' : '#111827';
78
+ const dayBg = isOtherMonth ? 'var(--fc-background-hover)' : 'var(--fc-background)';
79
+ const dayNumColor = isOtherMonth ? 'var(--fc-text-light)' : 'var(--fc-text-color)';
80
80
  const todayStyle = isToday
81
- ? 'background: #2563eb; color: white; border-radius: 50%; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;'
81
+ ? 'background: var(--fc-primary-color); color: white; border-radius: 50%; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;'
82
82
  : '';
83
83
 
84
84
  const events = day.events || [];
@@ -87,13 +87,13 @@ export class MonthViewRenderer extends BaseViewRenderer {
87
87
 
88
88
  return `
89
89
  <div class="fc-month-day" data-date="${day.date}"
90
- style="background: ${dayBg}; border-right: 1px solid #e5e7eb; border-bottom: 1px solid #e5e7eb; padding: 4px; min-height: 80px; cursor: pointer; display: flex; flex-direction: column;">
90
+ style="background: ${dayBg}; border-right: 1px solid var(--fc-border-color); border-bottom: 1px solid var(--fc-border-color); padding: 4px; min-height: 80px; cursor: pointer; display: flex; flex-direction: column;">
91
91
  <div class="fc-day-number" style="font-size: 13px; font-weight: 500; color: ${dayNumColor}; padding: 2px 4px; margin-bottom: 4px; ${todayStyle}">
92
92
  ${day.dayOfMonth}
93
93
  </div>
94
94
  <div class="fc-day-events" style="display: flex; flex-direction: column; gap: 2px; flex: 1; overflow: hidden;">
95
95
  ${visibleEvents.map(evt => this._renderEvent(evt)).join('')}
96
- ${moreCount > 0 ? `<div class="fc-more-events" style="font-size: 10px; color: #6b7280; padding: 2px 4px; font-weight: 500;">+${moreCount} more</div>` : ''}
96
+ ${moreCount > 0 ? `<div class="fc-more-events" style="font-size: 10px; color: var(--fc-text-light); padding: 2px 4px; font-weight: 500;">+${moreCount} more</div>` : ''}
97
97
  </div>
98
98
  </div>
99
99
  `;
@@ -19,7 +19,7 @@ export class WeekViewRenderer extends BaseViewRenderer {
19
19
  const viewData = this.stateManager.getViewData();
20
20
  if (!viewData || !viewData.days || viewData.days.length === 0) {
21
21
  this.container.innerHTML =
22
- '<div style="padding: 20px; text-align: center; color: #666;">No data available for week view.</div>';
22
+ '<div style="padding: 20px; text-align: center; color: var(--fc-text-secondary);">No data available for week view.</div>';
23
23
  return;
24
24
  }
25
25
 
@@ -53,7 +53,7 @@ export class WeekViewRenderer extends BaseViewRenderer {
53
53
  });
54
54
 
55
55
  return `
56
- <div class="fc-week-view" style="display: flex; flex-direction: column; height: 100%; background: #fff; overflow: hidden;">
56
+ <div class="fc-week-view" style="display: flex; flex-direction: column; height: 100%; background: var(--fc-background); overflow: hidden;">
57
57
  ${this._renderHeader(processedDays)}
58
58
  ${this._renderAllDayRow(processedDays)}
59
59
  ${this._renderTimeGrid(processedDays, hours)}
@@ -63,16 +63,16 @@ export class WeekViewRenderer extends BaseViewRenderer {
63
63
 
64
64
  _renderHeader(days) {
65
65
  return `
66
- <div class="fc-week-header" style="display: grid; grid-template-columns: 60px repeat(7, 1fr); border-bottom: 1px solid #e5e7eb; background: #f9fafb; flex-shrink: 0;">
67
- <div style="border-right: 1px solid #e5e7eb;"></div>
66
+ <div class="fc-week-header" style="display: grid; grid-template-columns: 60px repeat(7, 1fr); border-bottom: 1px solid var(--fc-border-color); background: var(--fc-background-alt); flex-shrink: 0;">
67
+ <div style="border-right: 1px solid var(--fc-border-color);"></div>
68
68
  ${days
69
69
  .map(
70
70
  day => `
71
- <div style="padding: 12px 8px; text-align: center; border-right: 1px solid #e5e7eb;">
72
- <div style="font-size: 10px; font-weight: 700; color: #6b7280; text-transform: uppercase; letter-spacing: 0.1em;">
71
+ <div style="padding: 12px 8px; text-align: center; border-right: 1px solid var(--fc-border-color);">
72
+ <div style="font-size: 10px; font-weight: 700; color: var(--fc-text-light); text-transform: uppercase; letter-spacing: 0.1em;">
73
73
  ${day.dayName}
74
74
  </div>
75
- <div style="font-size: 16px; font-weight: 500; margin-top: 4px; ${day.isToday ? 'background: #dc2626; color: white; border-radius: 50%; width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;' : 'color: #111827;'}">
75
+ <div style="font-size: 16px; font-weight: 500; margin-top: 4px; ${day.isToday ? 'background: var(--fc-danger-color); color: white; border-radius: 50%; width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;' : 'color: var(--fc-text-color);'}">
76
76
  ${day.dayOfMonth}
77
77
  </div>
78
78
  </div>
@@ -85,14 +85,14 @@ export class WeekViewRenderer extends BaseViewRenderer {
85
85
 
86
86
  _renderAllDayRow(days) {
87
87
  return `
88
- <div class="fc-all-day-row" style="display: grid; grid-template-columns: 60px repeat(7, 1fr); border-bottom: 1px solid #e5e7eb; background: #fafafa; min-height: 32px; flex-shrink: 0;">
89
- <div style="font-size: 9px; color: #6b7280; display: flex; align-items: center; justify-content: center; border-right: 1px solid #e5e7eb; text-transform: uppercase; font-weight: 700;">
88
+ <div class="fc-all-day-row" style="display: grid; grid-template-columns: 60px repeat(7, 1fr); border-bottom: 1px solid var(--fc-border-color); background: var(--fc-background-alt); min-height: 32px; flex-shrink: 0;">
89
+ <div style="font-size: 9px; color: var(--fc-text-light); display: flex; align-items: center; justify-content: center; border-right: 1px solid var(--fc-border-color); text-transform: uppercase; font-weight: 700;">
90
90
  All day
91
91
  </div>
92
92
  ${days
93
93
  .map(
94
94
  day => `
95
- <div class="fc-all-day-cell" data-date="${day.date.toISOString()}" style="border-right: 1px solid #e5e7eb; padding: 4px; display: flex; flex-direction: column; gap: 2px;">
95
+ <div class="fc-all-day-cell" data-date="${day.date.toISOString()}" style="border-right: 1px solid var(--fc-border-color); padding: 4px; display: flex; flex-direction: column; gap: 2px;">
96
96
  ${day.allDayEvents
97
97
  .map(
98
98
  evt => `
@@ -124,11 +124,11 @@ export class WeekViewRenderer extends BaseViewRenderer {
124
124
 
125
125
  _renderTimeGutter(hours) {
126
126
  return `
127
- <div class="fc-time-gutter" style="border-right: 1px solid #e5e7eb; background: #fafafa;">
127
+ <div class="fc-time-gutter" style="border-right: 1px solid var(--fc-border-color); background: var(--fc-background-alt);">
128
128
  ${hours
129
129
  .map(
130
130
  h => `
131
- <div style="height: ${this.hourHeight}px; font-size: 10px; color: #6b7280; text-align: right; padding-right: 8px; font-weight: 500;">
131
+ <div style="height: ${this.hourHeight}px; font-size: 10px; color: var(--fc-text-light); text-align: right; padding-right: 8px; font-weight: 500;">
132
132
  ${h === 0 ? '' : this.formatHour(h)}
133
133
  </div>
134
134
  `
@@ -140,9 +140,9 @@ export class WeekViewRenderer extends BaseViewRenderer {
140
140
 
141
141
  _renderDayColumn(day, hours) {
142
142
  return `
143
- <div class="fc-week-day-column" data-date="${day.date.toISOString()}" style="border-right: 1px solid #e5e7eb; position: relative; cursor: pointer;">
143
+ <div class="fc-week-day-column" data-date="${day.date.toISOString()}" style="border-right: 1px solid var(--fc-border-color); position: relative; cursor: pointer;">
144
144
  <!-- Hour grid lines -->
145
- ${hours.map(() => `<div style="height: ${this.hourHeight}px; border-bottom: 1px solid #f3f4f6;"></div>`).join('')}
145
+ ${hours.map(() => `<div style="height: ${this.hourHeight}px; border-bottom: 1px solid var(--fc-background-hover);"></div>`).join('')}
146
146
 
147
147
  <!-- Now indicator for today -->
148
148
  ${day.isToday ? this.renderNowIndicator() : ''}