server-time-timer-yolabs-ui 1.0.12 → 1.0.13

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
@@ -1,35 +1,33 @@
1
1
 
2
2
  # ⏱️ server-time-timer-yolabs-ui
3
3
 
4
- **SharePoint-styled React countdown timer UI built on top of `server-time-timer-yolabs`.**
5
-
6
- A **professional, enterprise-grade React UI** for **server-synchronized countdown timers**.
7
- Designed for **accuracy, consistency, and corporate dashboards**.
4
+ **SharePoint-styled React countdown timer UI** built on top of `server-time-timer-yolabs`.
5
+ Enterprise-grade, **server-synchronized countdown timers** designed for accuracy, consistency, and corporate dashboards.
8
6
 
9
7
  ---
10
8
 
11
9
  ## 🚀 Why Use This UI?
12
10
 
13
- Unlike traditional timers that rely on the **client’s local clock**, this UI uses **server time as the single source of truth**.
11
+ Unlike traditional timers that rely on the **client’s clock**, this UI uses **server time as the single source of truth**.
14
12
 
15
13
  ### ✅ Key Advantages
16
14
 
17
- * 🔒 **Server-trusted time** → no client clock manipulation
18
- * 🌍 **Consistent countdown across all devices**
19
- * 🧩 **Dynamic layouts, sizes, themes, and colors**
20
- * ⚡ **Optional animated progress bar**
21
- * 🕒 **Configurable units** (days, hours, minutes, seconds)
22
- * 🏢 **Enterprise UI** inspired by Fluent UI / SharePoint
15
+ * 🔒 Server-trusted time → no client clock manipulation
16
+ * 🌍 Consistent countdown across all devices
17
+ * 🧩 Dynamic layouts, sizes, themes, and colors
18
+ * ⚡ Optional animated progress bar
19
+ * 🕒 Configurable units (days, hours, minutes, seconds)
20
+ * 🏢 Enterprise UI inspired by Fluent UI / SharePoint
23
21
 
24
22
  ---
25
23
 
26
- ## ⚡ Difference From Other Timers
24
+ ## ⚡ Difference From Normal Timers
27
25
 
28
26
  | Feature | Normal Timers | server-time-timer-yolabs-ui |
29
27
  | ------------------------ | --------------- | --------------------------------- |
30
28
  | Time Source | Client | **Server (trusted)** |
31
29
  | Cross-Device Consistency | ❌ Can differ | ✅ Always same |
32
- | Time Drift Handling | ❌ None | ✅ Auto-corrected |
30
+ | Drift Handling | ❌ None | ✅ Auto-corrected |
33
31
  | Layouts | ❌ Fixed | ✅ Horizontal / Vertical / Compact |
34
32
  | Unit Visibility | ❌ Fixed | ✅ Per-unit control |
35
33
  | Progress Bar | ❌ Missing | ✅ Built-in |
@@ -60,29 +58,17 @@ import { ServerTimerUI } from 'server-time-timer-yolabs-ui';
60
58
  export default function App() {
61
59
  return (
62
60
  <ServerTimerUI
63
- serverNow="2025-12-25T12:00:00Z"
64
61
  endTime="2025-12-25T12:10:00Z"
65
-
66
62
  size="lg"
67
63
  layout="horizontal"
68
64
  theme="brand"
69
-
70
- showProgress={true}
71
-
65
+ showUnits={{ days: true, hours: true, minutes: true, seconds: true }}
72
66
  customColors={{
73
67
  background: '#fef9f3',
74
68
  text: '#323130',
75
69
  unitBackground: '#fffbdd',
76
70
  progress: '#0078d4'
77
71
  }}
78
-
79
- showUnits={{
80
- days: true,
81
- hours: true,
82
- minutes: true,
83
- seconds: true
84
- }}
85
-
86
72
  onEnd={() => alert('⏰ Time is up!')}
87
73
  />
88
74
  );
@@ -95,9 +81,6 @@ export default function App() {
95
81
 
96
82
  ```ts
97
83
  export interface ServerTimerUIProps {
98
- /** Server UTC time (ISO string) */
99
- serverNow: string;
100
-
101
84
  /** Countdown end UTC time (ISO string) */
102
85
  endTime: string;
103
86
 
@@ -110,11 +93,13 @@ export interface ServerTimerUIProps {
110
93
  /** Built-in theme */
111
94
  theme?: 'light' | 'dark' | 'brand';
112
95
 
113
- /** Show animated progress bar */
114
- showProgress?: boolean;
115
-
116
- /** Called once when timer reaches zero */
117
- onEnd?: () => void;
96
+ /** Show time units */
97
+ showUnits?: {
98
+ days?: boolean;
99
+ hours?: boolean;
100
+ minutes?: boolean;
101
+ seconds?: boolean;
102
+ };
118
103
 
119
104
  /** Optional wrapper class */
120
105
  className?: string;
@@ -127,13 +112,8 @@ export interface ServerTimerUIProps {
127
112
  progress?: string;
128
113
  };
129
114
 
130
- /** Control visible time units */
131
- showUnits?: {
132
- days?: boolean;
133
- hours?: boolean;
134
- minutes?: boolean;
135
- seconds?: boolean;
136
- };
115
+ /** Callback when timer ends */
116
+ onEnd?: () => void;
137
117
  }
138
118
  ```
139
119
 
@@ -141,34 +121,17 @@ export interface ServerTimerUIProps {
141
121
 
142
122
  ## 🎨 Layouts
143
123
 
144
- ### Horizontal (default)
145
-
146
- Units displayed in a row.
147
- ✔ Dashboards
148
- ✔ Desktop views
149
-
150
- ### Vertical
151
-
152
- Units stacked vertically.
153
- ✔ Mobile
154
- ✔ Side panels
155
-
156
- ### Compact
157
-
158
- Minimal, label-free layout.
159
- ✔ Cards
160
- ✔ Headers
161
- ✔ Space-constrained UIs
124
+ * **Horizontal (default)** – units in a row, ideal for dashboards and desktop views
125
+ * **Vertical** – stacked units, best for mobile or side panels
126
+ * **Compact** – minimal, label-free, fits in cards or headers
162
127
 
163
128
  ---
164
129
 
165
130
  ## 🎭 Themes
166
131
 
167
- Built-in themes are located in the `themes` folder:
168
-
169
- * `light` – light style
132
+ * `light` Light UI
170
133
  * `dark` – Enterprise dark mode
171
- * `brand` – Corporate / SharePoint branding
134
+ * `brand` – Corporate / SharePoint styling
172
135
 
173
136
  ```tsx
174
137
  <ServerTimerUI theme="dark" />
@@ -187,8 +150,8 @@ customColors={{
187
150
  }}
188
151
  ```
189
152
 
190
- Optional
191
- Automatically overrides theme defaults
153
+ * Overrides theme defaults
154
+ * Optional
192
155
 
193
156
  ---
194
157
 
@@ -203,27 +166,22 @@ showUnits={{
203
166
  }}
204
167
  ```
205
168
 
206
- Hide unused units
207
- Cleaner UI for short timers
169
+ * Hide unused units for a cleaner UI
170
+ * Useful for short timers
208
171
 
209
172
  ---
210
173
 
211
- ## 📱 Responsiveness & Overflow Safety
174
+ ## 📱 Responsive & Safe
212
175
 
213
176
  * Uses `flex-wrap` to prevent overflow
214
- * Auto-scales typography by `size`
215
- * Vertical layout recommended for small screens
177
+ * Auto-scales typography based on `size`
216
178
  * Numbers never jump or resize unexpectedly
217
-
218
- ✔ Mobile-safe
219
- ✔ Dashboard-safe
179
+ * Vertical layout recommended for small screens
220
180
 
221
181
  ---
222
182
 
223
183
  ## 🔁 Server Re-Sync (Long Timers)
224
184
 
225
- For long-running timers, periodically resync with the server:
226
-
227
185
  ```ts
228
186
  setInterval(async () => {
229
187
  const res = await fetch('/api/server-time');
@@ -232,40 +190,36 @@ setInterval(async () => {
232
190
  }, 30000);
233
191
  ```
234
192
 
235
- Prevents long-term drift
236
- Enterprise-grade accuracy
193
+ * Prevents long-term drift
194
+ * Enterprise-grade accuracy
237
195
 
238
196
  ---
239
197
 
240
- ## 🔧 Angular / Framework-Agnostic Usage
198
+ ## 🔧 Framework-Agnostic Usage
241
199
 
242
- For Angular, Vue, or Vanilla JS, use the **core engine**:
200
+ Use the **core engine** (`server-time-timer-yolabs`) for Angular, Vue, or Vanilla JS:
243
201
 
244
202
  ```ts
245
203
  import { createServerTimer } from 'server-time-timer-yolabs';
246
204
 
247
205
  const timer = createServerTimer({
248
- serverNow: new Date().toISOString(),
249
206
  endTime: new Date(Date.now() + 10 * 60 * 1000).toISOString()
250
207
  });
251
208
 
252
- timer.onTick((t) => {
253
- console.log(`${t.hours}h ${t.minutes}m ${t.seconds}s`);
254
- });
255
-
209
+ timer.onTick(t => console.log(`${t.hours}h ${t.minutes}m ${t.seconds}s`));
256
210
  timer.start();
257
211
  ```
258
212
 
259
- Wrap values in your own UI layer
260
- React UI package remains optional
213
+ * Wrap values in your own UI
214
+ * React UI package remains optional
261
215
 
262
216
  ---
263
217
 
264
- ## 🏢 Common Use Cases
218
+ ## 🏢 Use Cases
265
219
 
266
220
  * 🎟️ Lottery & raffle systems
267
221
  * 🛒 Flash sales & promotions
268
- * 📝 Online exams & quizzes
222
+ * 📝 Online exams & timed quizzes
269
223
  * 🎮 Games & live events
270
224
  * 📱 Telegram Mini Apps
271
225
  * 🌐 Distributed enterprise dashboards
@@ -275,17 +229,17 @@ timer.start();
275
229
 
276
230
  ## 📜 License
277
231
 
278
- **Yonas**
279
- © **YoLabs**
232
+ **YonasLabs / YoLabs**
280
233
 
281
234
  ---
282
235
 
283
- ## ✅ Final Notes
236
+ ## ✅ Notes
284
237
 
285
- This package is designed for **mission-critical timers** where:
238
+ Designed for **mission-critical timers**:
286
239
 
287
240
  * Accuracy matters
288
- * Client manipulation must be avoided
289
- * UI consistency is required across platforms
241
+ * Client manipulation is prevented
242
+ * UI consistency across platforms is guaranteed
290
243
 
291
244
  ---
245
+
@@ -1,37 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const jsx_runtime_1 = require("react/jsx-runtime");
4
- const paddingMap = {
5
- sm: '0.5rem 1rem',
6
- md: '1rem 1.5rem',
7
- lg: '1.5rem 2rem',
8
- };
9
4
  const gapMap = {
10
5
  horizontal: '0.625rem',
11
6
  vertical: '0.625rem',
12
7
  compact: '0.25rem',
13
8
  };
14
9
  const TimerContainer = ({ children, size = 'md', className = '', background = '#ffffff', color = '#323130', layout = 'horizontal', }) => {
15
- const getFlexStyles = () => {
16
- switch (layout) {
17
- case 'vertical':
18
- return {
19
- flexDirection: 'column',
20
- flexWrap: 'nowrap',
21
- };
22
- case 'compact':
23
- return {
24
- flexDirection: 'row',
25
- flexWrap: 'wrap',
26
- };
27
- default: // horizontal
28
- return {
29
- flexDirection: 'row',
30
- flexWrap: 'nowrap',
31
- };
32
- }
33
- };
34
- const flexStyles = getFlexStyles();
35
- return ((0, jsx_runtime_1.jsx)("div", { className: `timer-container ${className}`, style: Object.assign(Object.assign({ display: 'flex' }, flexStyles), { alignItems: 'center', justifyContent: 'center', gap: gapMap[layout], backgroundColor: background, color: color, border: '1px solid #e1e1e1', borderRadius: '4px', padding: paddingMap[size], fontFamily: `'Segoe UI', -apple-system, BlinkMacSystemFont, sans-serif`, fontSize: '1rem', overflow: 'hidden', transition: 'all 0.2s ease', boxSizing: 'border-box', minWidth: layout === 'compact' ? 'fit-content' : undefined }), role: "timer", "aria-label": "timer container", children: children }));
10
+ const flexStyles = {
11
+ horizontal: { flexDirection: 'row', flexWrap: 'nowrap' },
12
+ vertical: { flexDirection: 'column', flexWrap: 'nowrap' },
13
+ compact: { flexDirection: 'row', flexWrap: 'wrap' },
14
+ }[layout]; // <--- cast here
15
+ return ((0, jsx_runtime_1.jsx)("div", { className: `timer-container ${className}`, style: Object.assign(Object.assign({ display: 'flex' }, flexStyles), { alignItems: 'center', justifyContent: 'center', gap: gapMap[layout], backgroundColor: background, color: color, border: '1px solid #e1e1e1', borderRadius: '6px', padding: size === 'sm' ? '0.25rem' : size === 'md' ? '0.5rem' : '0.75rem', fontFamily: `'Segoe UI', -apple-system, BlinkMacSystemFont, sans-serif`, fontSize: '1rem', overflow: 'hidden', boxSizing: 'border-box', transition: 'all 0.2s ease' }), role: "timer", "aria-label": "timer container", children: children }));
36
16
  };
37
17
  exports.default = TimerContainer;
@@ -6,8 +6,7 @@ interface TimerUnitProps {
6
6
  size?: TimerSize;
7
7
  background?: string;
8
8
  color?: string;
9
- leadingZero?: boolean;
10
- monospace?: boolean;
9
+ numberSize?: 'sm' | 'md' | 'lg';
11
10
  }
12
11
  declare const TimerUnit: React.FC<TimerUnitProps>;
13
12
  export default TimerUnit;
@@ -1,56 +1,45 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const jsx_runtime_1 = require("react/jsx-runtime");
4
- const TimerUnit = ({ label, value, size = 'md', background = '#ffffff', color = '#333333', leadingZero = true, monospace = true, }) => {
5
- const sizeStyles = {
6
- sm: {
7
- container: 'p-2 min-w-12',
8
- value: 'text-lg font-semibold',
9
- label: 'text-xs'
10
- },
11
- md: {
12
- container: 'p-3 min-w-16',
13
- value: 'text-2xl font-bold',
14
- label: 'text-sm'
15
- },
16
- lg: {
17
- container: 'p-4 min-w-20',
18
- value: 'text-3xl font-extrabold',
19
- label: 'text-base'
20
- }
21
- };
22
- const formattedValue = leadingZero ?
23
- value.toString().padStart(2, '0') :
24
- value.toString();
25
- const fontFamily = monospace ?
26
- 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace' :
27
- 'inherit';
4
+ const fontSizeMap = {
5
+ sm: '0.75rem', // label font
6
+ md: '0.875rem',
7
+ lg: '1rem',
8
+ };
9
+ const numberFontMap = {
10
+ sm: '1rem',
11
+ md: '1.25rem',
12
+ lg: '1.5rem',
13
+ };
14
+ const paddingMap = {
15
+ sm: '0.25rem 0.5rem',
16
+ md: '0.5rem 0.75rem',
17
+ lg: '0.75rem 1rem',
18
+ };
19
+ const TimerUnit = ({ label, value, size = 'md', background = '#f3f2f1', color = '#323130', numberSize = 'md', }) => {
28
20
  return ((0, jsx_runtime_1.jsxs)("div", { style: {
29
- backgroundColor: background,
30
- color: color,
31
- padding: size === 'sm' ? '0.5rem' : size === 'lg' ? '1rem' : '0.75rem',
32
- borderRadius: '0.5rem',
33
- textAlign: 'center',
34
- minWidth: size === 'sm' ? '3rem' : size === 'lg' ? '5rem' : '4rem',
35
21
  display: 'flex',
36
22
  flexDirection: 'column',
37
23
  alignItems: 'center',
38
24
  justifyContent: 'center',
39
- border: '1px solid #e5e5e5',
40
- boxShadow: '0 1px 3px rgba(0,0,0,0.04)',
41
- }, "aria-label": `${formattedValue} ${label}`, children: [(0, jsx_runtime_1.jsx)("div", { style: {
42
- fontSize: size === 'sm' ? '1.125rem' : size === 'lg' ? '1.875rem' : '1.5rem',
43
- fontWeight: size === 'sm' ? 600 : size === 'lg' ? 800 : 700,
44
- lineHeight: 1.1,
45
- fontFamily: fontFamily,
46
- fontVariantNumeric: 'tabular-nums',
47
- marginBottom: '0.25rem',
48
- }, children: formattedValue }), (0, jsx_runtime_1.jsx)("div", { style: {
49
- fontSize: size === 'sm' ? '0.75rem' : size === 'lg' ? '1rem' : '0.875rem',
50
- fontWeight: 500,
25
+ backgroundColor: background,
26
+ color: color,
27
+ borderRadius: '6px',
28
+ padding: paddingMap[size],
29
+ minWidth: size === 'sm' ? '3rem' : size === 'md' ? '4rem' : '5rem',
30
+ boxShadow: '0 1px 3px rgba(0,0,0,0.1)',
31
+ transition: 'all 0.2s ease',
32
+ boxSizing: 'border-box',
33
+ fontFamily: `'Segoe UI', -apple-system, BlinkMacSystemFont, sans-serif`,
34
+ }, children: [(0, jsx_runtime_1.jsx)("span", { style: {
35
+ fontSize: numberFontMap[numberSize],
36
+ fontWeight: 600,
37
+ lineHeight: 1,
38
+ }, children: value.toString().padStart(2, '0') }), (0, jsx_runtime_1.jsx)("span", { style: {
39
+ fontSize: fontSizeMap[size],
40
+ marginTop: '0.25rem',
51
41
  textTransform: 'uppercase',
52
- letterSpacing: '0.05em',
53
- opacity: 0.7,
42
+ whiteSpace: 'nowrap',
54
43
  }, children: label })] }));
55
44
  };
56
45
  exports.default = TimerUnit;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "server-time-timer-yolabs-ui",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "FluentUI/SharePoint styled React countdown timer UI for server-time-timer-yoLabs",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",