tgwidget 0.1.0 → 0.1.2

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
@@ -38,13 +38,19 @@ When a user completes the widget, the result comes back via deep link `t.me/your
38
38
  ```typescript
39
39
  import { parseDate, parseColor, parseSchedule } from "tgwidget";
40
40
 
41
- // Date result
41
+ // Date result — includes native Date object
42
42
  const result = parseDate("2025-03-15", { mode: "date" });
43
- // { date: '2025-03-15' }
43
+ // result.date === '2025-03-15'
44
+ // result.dateObj === Date(2025, 2, 15)
45
+
46
+ // Datetime — native Date with time set
47
+ const result = parseDate("2025-03-15_14-30", { mode: "datetime" });
48
+ // result.dateObj — Date object with date and time
44
49
 
45
50
  // Unix timestamp
46
51
  const result = parseDate("1710460800_1718236800", { mode: "date-range", format: "unix-s" });
47
- // { timestamp: 1710460800, timestampEnd: 1718236800, date: '2025-03-15', ... }
52
+ // result.dateObj, result.dateEndObj native Date objects
53
+ // result.timestamp === 1710460800
48
54
 
49
55
  // Color
50
56
  const result = parseColor("FF6600", { format: "hex" });
@@ -55,21 +61,84 @@ const result = parseSchedule("09001800090018000000000009001800090018000000000000
55
61
  // [{ enabled: true, start: '09:00', end: '18:00' }, ...]
56
62
  ```
57
63
 
64
+ All parsers automatically handle Telegram bot command prefixes — you can pass raw `/start payload` strings directly:
65
+
66
+ ```typescript
67
+ const result = parseDate("/start 2025-03-15", { mode: "date" });
68
+ // result.dateObj — Date(2025, 2, 15)
69
+
70
+ const result = parseColor("/start FF6600", { format: "hex" });
71
+ // result.hex === '#FF6600'
72
+ ```
73
+
74
+ ### Pattern (informational format string)
75
+
76
+ Each widget exposes a `.pattern` property — a human-readable format hint you can show to users:
77
+
78
+ ```typescript
79
+ const widget = tgwidget("your_bot").date({ mode: "datetime" });
80
+ widget.pattern; // "YYYY-MM-DD HH:MM"
81
+
82
+ const widget2 = tgwidget("your_bot").date({ mode: "date", order: "dmy" });
83
+ widget2.pattern; // "DD-MM-YYYY"
84
+
85
+ const widget3 = tgwidget("your_bot").color({ format: "hex" });
86
+ widget3.pattern; // "#RRGGBB"
87
+
88
+ // Use in bot messages:
89
+ await ctx.reply(`Введите дату в формате ${widget.pattern}`);
90
+ ```
91
+
92
+ You can also use the standalone `getPattern(widget, payload)` function directly.
93
+
94
+ ### Widget-level parsing with `parse()`
95
+
96
+ If you keep a reference to the widget builder, you can call `.parse()` directly — it automatically uses the configured widget type and options. The return type is inferred from the widget type:
97
+
98
+ ```typescript
99
+ const widget = tgwidget("your_bot").date({ mode: "datetime" });
100
+ const url = widget.url();
101
+
102
+ // Later, when the user completes the widget:
103
+ const result = widget.parse("/start 2025-03-15_14-30");
104
+ // result is DateResult (type-safe!)
105
+ // result.dateObj — native Date object
106
+ ```
107
+
58
108
  ## API
59
109
 
60
110
  ### `tgwidget(botUsername)`
61
111
 
62
112
  Create a widget builder. Returns a chainable `TgWidget` instance.
63
113
 
64
- - `.date({ mode?, format?, order? })` — Date/time picker
65
- - `.color({ format? })` — Color picker
66
- - `.schedule()` — Weekly schedule
114
+ - `.date({ mode?, format?, order? })` — Date/time picker → `TgWidget<"date">`
115
+ - `.color({ format? })` — Color picker → `TgWidget<"color">`
116
+ - `.schedule()` — Weekly schedule → `TgWidget<"schedule">`
67
117
  - `.style({ colorScheme?, accent?, tint?, liquidGlass?, adaptTgTheme?, adoptTgPalette? })` — Styling
68
118
  - `.url(baseUrl?)` — Generate the final URL
69
119
  - `.payload()` — Get the raw payload object
120
+ - `.pattern` — Human-readable format string (e.g. `"YYYY-MM-DD HH:MM"`)
121
+ - `.parse(value)` — Parse a widget result string (return type matches widget type)
70
122
 
71
123
  ### Parsers
72
124
 
73
125
  - `parseDate(value, { mode?, format?, order? })` → `DateResult`
74
126
  - `parseColor(value, { format? })` → `ColorResult`
75
127
  - `parseSchedule(value)` → `ScheduleDay[]`
128
+
129
+ ### Result types
130
+
131
+ #### `DateResult`
132
+ - `date`, `time`, `dateEnd`, `timeEnd` — string representations
133
+ - `timestamp`, `timestampEnd` — raw integer timestamps (unix modes)
134
+ - `dateObj`, `dateEndObj` — native `Date` objects
135
+
136
+ #### `ColorResult`
137
+ - `raw` — original value string
138
+ - `hex` — e.g. `'#FF6600'`
139
+ - `rgb` — e.g. `[255, 102, 0]`
140
+ - `hsl` — e.g. `[24, 100, 50]`
141
+
142
+ #### `ScheduleDay`
143
+ - `enabled` — whether the day is active
144
+ - `start`, `end` — time strings e.g. `'09:00'`
package/dist/builder.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { DateMode, DateFormat, DateOrder, ColorFormat, ColorScheme } from "./types";
2
- export declare class TgWidget {
1
+ import type { DateMode, DateFormat, DateOrder, ColorFormat, ColorScheme, WidgetType, ParseResult } from "./types";
2
+ export declare class TgWidget<T extends WidgetType | null = null> {
3
3
  private _botUsername;
4
4
  private _widget;
5
5
  private _payload;
@@ -9,11 +9,11 @@ export declare class TgWidget {
9
9
  mode?: DateMode;
10
10
  format?: DateFormat;
11
11
  order?: DateOrder;
12
- }): this;
12
+ }): TgWidget<"date">;
13
13
  color(opts?: {
14
14
  format?: ColorFormat;
15
- }): this;
16
- schedule(): this;
15
+ }): TgWidget<"color">;
16
+ schedule(): TgWidget<"schedule">;
17
17
  style(opts?: {
18
18
  colorScheme?: ColorScheme;
19
19
  accent?: string;
@@ -25,5 +25,7 @@ export declare class TgWidget {
25
25
  private _buildPayload;
26
26
  url(baseUrl?: string): string;
27
27
  payload(): Record<string, unknown>;
28
+ get pattern(): string;
29
+ parse(value: string): ParseResult<T>;
28
30
  }
29
31
  export declare function tgwidget(botUsername: string): TgWidget;
package/dist/builder.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { parseDate, parseColor, parseSchedule } from "./parser";
2
+ import { getPattern } from "./pattern";
1
3
  const BASE_URL = "https://tgwidget.github.io/";
2
4
  const HEX_RE = /^#?[0-9A-Fa-f]{6}$/;
3
5
  const VALID_DATE_MODES = new Set(["date", "time", "datetime", "date-range", "time-range"]);
@@ -83,6 +85,23 @@ export class TgWidget {
83
85
  payload() {
84
86
  return this._buildPayload();
85
87
  }
88
+ get pattern() {
89
+ if (!this._widget)
90
+ throw new Error("No widget type set. Call .date(), .color(), or .schedule() first.");
91
+ return getPattern(this._widget, this._payload);
92
+ }
93
+ parse(value) {
94
+ if (this._widget === "date") {
95
+ return parseDate(value, this._payload);
96
+ }
97
+ if (this._widget === "color") {
98
+ return parseColor(value, this._payload);
99
+ }
100
+ if (this._widget === "schedule") {
101
+ return parseSchedule(value);
102
+ }
103
+ throw new Error("No widget type set. Call .date(), .color(), or .schedule() first.");
104
+ }
86
105
  }
87
106
  export function tgwidget(botUsername) {
88
107
  return new TgWidget(botUsername);
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { tgwidget, TgWidget } from "./builder";
2
2
  export { parseDate, parseColor, parseSchedule } from "./parser";
3
- export type { DateMode, DateFormat, DateOrder, ColorFormat, ColorScheme, WidgetStyle, DateResult, ColorResult, ScheduleDay, } from "./types";
3
+ export { getPattern } from "./pattern";
4
+ export type { DateMode, DateFormat, DateOrder, ColorFormat, ColorScheme, WidgetType, WidgetStyle, DateResult, ColorResult, ScheduleDay, ParseResult, } from "./types";
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { tgwidget, TgWidget } from "./builder";
2
2
  export { parseDate, parseColor, parseSchedule } from "./parser";
3
+ export { getPattern } from "./pattern";
package/dist/parser.js CHANGED
@@ -1,3 +1,11 @@
1
+ function stripCommand(value) {
2
+ if (value.startsWith("/")) {
3
+ const idx = value.indexOf(" ");
4
+ if (idx !== -1)
5
+ return value.slice(idx + 1);
6
+ }
7
+ return value;
8
+ }
1
9
  function parseDateStr(value, order) {
2
10
  const parts = value.split("-");
3
11
  if (order === "ymd")
@@ -6,7 +14,12 @@ function parseDateStr(value, order) {
6
14
  return `${parts[2]}-${parts[1]}-${parts[0]}`;
7
15
  return `${parts[2]}-${parts[0]}-${parts[1]}`; // mdy
8
16
  }
17
+ function dateFromYmd(ymdStr) {
18
+ const [y, m, d] = ymdStr.split("-").map(Number);
19
+ return new Date(y, m - 1, d);
20
+ }
9
21
  export function parseDate(value, opts = {}) {
22
+ value = stripCommand(value);
10
23
  const { mode = "date", format = "default", order = "ymd" } = opts;
11
24
  const result = {};
12
25
  if (format === "unix-s" || format === "unix-ms") {
@@ -15,21 +28,26 @@ export function parseDate(value, opts = {}) {
15
28
  const ts = parseInt(parts[0], 10);
16
29
  result.timestamp = ts;
17
30
  const dt = new Date(ts * mul);
31
+ result.dateObj = dt;
18
32
  result.date = dt.toISOString().slice(0, 10);
19
33
  result.time = dt.toISOString().slice(11, 16);
20
34
  if (parts.length > 1) {
21
35
  const tsEnd = parseInt(parts[1], 10);
22
36
  result.timestampEnd = tsEnd;
23
37
  const dtEnd = new Date(tsEnd * mul);
38
+ result.dateEndObj = dtEnd;
24
39
  result.dateEnd = dtEnd.toISOString().slice(0, 10);
25
40
  result.timeEnd = dtEnd.toISOString().slice(11, 16);
26
41
  }
27
42
  return result;
28
43
  }
29
44
  switch (mode) {
30
- case "date":
31
- result.date = parseDateStr(value, order);
45
+ case "date": {
46
+ const dateStr = parseDateStr(value, order);
47
+ result.date = dateStr;
48
+ result.dateObj = dateFromYmd(dateStr);
32
49
  break;
50
+ }
33
51
  case "time": {
34
52
  const [h, m] = value.split("-");
35
53
  result.time = `${h}:${m}`;
@@ -37,15 +55,23 @@ export function parseDate(value, opts = {}) {
37
55
  }
38
56
  case "datetime": {
39
57
  const [datePart, timePart] = value.split("_");
40
- result.date = parseDateStr(datePart, order);
58
+ const dateStr = parseDateStr(datePart, order);
41
59
  const [h, m] = timePart.split("-");
60
+ result.date = dateStr;
42
61
  result.time = `${h}:${m}`;
62
+ const d = dateFromYmd(dateStr);
63
+ d.setHours(parseInt(h, 10), parseInt(m, 10), 0, 0);
64
+ result.dateObj = d;
43
65
  break;
44
66
  }
45
67
  case "date-range": {
46
68
  const parts = value.split("_");
47
- result.date = parseDateStr(parts[0], order);
48
- result.dateEnd = parseDateStr(parts[1], order);
69
+ const dateStr = parseDateStr(parts[0], order);
70
+ const dateEndStr = parseDateStr(parts[1], order);
71
+ result.date = dateStr;
72
+ result.dateEnd = dateEndStr;
73
+ result.dateObj = dateFromYmd(dateStr);
74
+ result.dateEndObj = dateFromYmd(dateEndStr);
49
75
  break;
50
76
  }
51
77
  case "time-range": {
@@ -60,6 +86,7 @@ export function parseDate(value, opts = {}) {
60
86
  return result;
61
87
  }
62
88
  export function parseColor(value, opts = {}) {
89
+ value = stripCommand(value);
63
90
  const { format = "hex" } = opts;
64
91
  const result = { raw: value };
65
92
  if (format === "hex") {
@@ -76,6 +103,7 @@ export function parseColor(value, opts = {}) {
76
103
  return result;
77
104
  }
78
105
  export function parseSchedule(value) {
106
+ value = stripCommand(value);
79
107
  if (value.length !== 56) {
80
108
  throw new Error(`Schedule bunch format must be 56 chars, got ${value.length}`);
81
109
  }
@@ -0,0 +1,2 @@
1
+ import type { WidgetType } from "./types";
2
+ export declare function getPattern(widget: WidgetType, payload: Record<string, unknown>): string;
@@ -0,0 +1,40 @@
1
+ const DATE_PATTERNS = {
2
+ ymd: "YYYY-MM-DD",
3
+ dmy: "DD-MM-YYYY",
4
+ mdy: "MM-DD-YYYY",
5
+ };
6
+ const TIME_PATTERN = "HH-MM";
7
+ export function getPattern(widget, payload) {
8
+ if (widget === "date") {
9
+ const mode = payload.mode ?? "date";
10
+ const order = payload.order ?? "ymd";
11
+ const datePat = DATE_PATTERNS[order];
12
+ switch (mode) {
13
+ case "date":
14
+ return datePat;
15
+ case "time":
16
+ return TIME_PATTERN;
17
+ case "datetime":
18
+ return `${datePat}_${TIME_PATTERN}`;
19
+ case "date-range":
20
+ return `${datePat}_${datePat}`;
21
+ case "time-range":
22
+ return `${TIME_PATTERN}_${TIME_PATTERN}`;
23
+ }
24
+ }
25
+ if (widget === "color") {
26
+ const format = payload.format ?? "hex";
27
+ switch (format) {
28
+ case "hex":
29
+ return "#RRGGBB";
30
+ case "rgb":
31
+ return "R, G, B";
32
+ case "hsl":
33
+ return "H, S, L";
34
+ }
35
+ }
36
+ if (widget === "schedule") {
37
+ return "HH:MM—HH:MM × 7 days";
38
+ }
39
+ return "";
40
+ }
package/dist/types.d.ts CHANGED
@@ -3,6 +3,7 @@ export type DateFormat = "default" | "unix-s" | "unix-ms";
3
3
  export type DateOrder = "ymd" | "dmy" | "mdy";
4
4
  export type ColorFormat = "hex" | "rgb" | "hsl";
5
5
  export type ColorScheme = "light" | "dark" | "auto";
6
+ export type WidgetType = "date" | "color" | "schedule";
6
7
  export interface WidgetStyle {
7
8
  colorScheme?: ColorScheme;
8
9
  accent?: string;
@@ -18,6 +19,8 @@ export interface DateResult {
18
19
  timeEnd?: string;
19
20
  timestamp?: number;
20
21
  timestampEnd?: number;
22
+ dateObj?: Date;
23
+ dateEndObj?: Date;
21
24
  }
22
25
  export interface ColorResult {
23
26
  raw: string;
@@ -30,3 +33,4 @@ export interface ScheduleDay {
30
33
  start?: string;
31
34
  end?: string;
32
35
  }
36
+ export type ParseResult<T extends WidgetType | null> = T extends "date" ? DateResult : T extends "color" ? ColorResult : T extends "schedule" ? ScheduleDay[] : DateResult | ColorResult | ScheduleDay[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tgwidget",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Node.js SDK for TeleWidget — Telegram Mini App widgets",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",