@wwog/react 1.2.2 → 1.2.3
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 +45 -16
- package/dist/index.d.mts +75 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/Common/DateRender.tsx +72 -0
- package/src/Common/index.ts +1 -0
- package/src/utils/index.ts +119 -0
package/README.md
CHANGED
|
@@ -150,13 +150,16 @@ function Example({ isActive }) {
|
|
|
150
150
|
```tsx
|
|
151
151
|
import { Toggle } from "@wwog/react";
|
|
152
152
|
|
|
153
|
-
<Toggle
|
|
153
|
+
<Toggle
|
|
154
|
+
options={["light", "dark"]}
|
|
155
|
+
render={(value, toggle) => {
|
|
156
|
+
/* xxx */
|
|
157
|
+
}}
|
|
158
|
+
/>;
|
|
154
159
|
```
|
|
155
160
|
|
|
156
161
|
- `options`:可切换的值数组。
|
|
157
162
|
- `index`:默认:0。
|
|
158
|
-
- `target`:传递切换值给子节点的属性名,默认 value。
|
|
159
|
-
- `toggleTarget`:传递切换函数给子节点的属性名,默认 toggle。
|
|
160
163
|
- `next`:自定义切换逻辑函数。
|
|
161
164
|
- `render`:渲染函数。
|
|
162
165
|
|
|
@@ -253,6 +256,37 @@ function Example() {
|
|
|
253
256
|
- `children`:作用域变量的渲染函数。
|
|
254
257
|
- `fallback`:无内容时的兜底渲染。
|
|
255
258
|
|
|
259
|
+
#### `<DateRender>` (v1.2.3+)
|
|
260
|
+
|
|
261
|
+
一个声明式组件,用于格式化并渲染日期,简单易用且支持自定义格式化。
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
import { DateRender } from "@wwog/react";
|
|
265
|
+
|
|
266
|
+
function Example() {
|
|
267
|
+
return (
|
|
268
|
+
<>
|
|
269
|
+
{/* 使用默认格式化 */}
|
|
270
|
+
<DateRender source="2025-05-06">
|
|
271
|
+
{(formatted) => <div>日期: {formatted}</div>}
|
|
272
|
+
</DateRender>
|
|
273
|
+
|
|
274
|
+
{/* 使用自定义格式化 */}
|
|
275
|
+
<DateRender
|
|
276
|
+
source={new Date()}
|
|
277
|
+
format={(date) => date.toLocaleDateString("zh-CN")}
|
|
278
|
+
>
|
|
279
|
+
{(formatted) => <div>日期: {formatted}</div>}
|
|
280
|
+
</DateRender>
|
|
281
|
+
</>
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
- `source`:要渲染的输入日期(Date 对象、ISO 字符串或时间戳)。
|
|
287
|
+
- `format`:可选的格式化日期的函数,默认使用 `toLocaleString()`。
|
|
288
|
+
- `children`:渲染格式化后日期的函数,接收格式化后的日期作为参数。
|
|
289
|
+
|
|
256
290
|
#### `<SizeBox>`
|
|
257
291
|
|
|
258
292
|
创建固定尺寸的容器,用于布局调整和间距控制。
|
|
@@ -278,25 +312,20 @@ function Layout() {
|
|
|
278
312
|
}
|
|
279
313
|
```
|
|
280
314
|
|
|
281
|
-
### Ideas
|
|
282
|
-
|
|
283
|
-
> 需求不高,但有用的组件
|
|
284
|
-
|
|
285
|
-
- Loop:灵活的迭代渲染,支持数组、对象和范围。
|
|
286
|
-
- Try:封装异步逻辑,处理 Promise 状态。
|
|
287
|
-
- Pick:轻量版值选择渲染,类似枚举匹配。
|
|
288
|
-
- Render:动态渲染函数,简化复杂渲染逻辑。
|
|
289
|
-
- Once:确保内容仅渲染一次,适合初始化。
|
|
290
|
-
- Each:增强列表渲染,支持过滤和排序。
|
|
291
|
-
|
|
292
315
|
### hooks
|
|
293
316
|
|
|
294
|
-
- 一些常用的hooks的封装
|
|
317
|
+
- 一些常用的 hooks 的封装
|
|
295
318
|
|
|
296
|
-
|
|
319
|
+
#### useControlled (v1.2.0+)
|
|
297
320
|
|
|
298
321
|
- 受控组件和非受控组件的切换,方便组件开发
|
|
299
322
|
|
|
323
|
+
### method
|
|
324
|
+
|
|
325
|
+
- 用于部分组件的内部函数,如需要也可使用
|
|
326
|
+
|
|
327
|
+
formatDate 比较标准的格式化时间函数
|
|
328
|
+
childrenLoop 可以中断的子节点遍历,让一些分支流程拥有极致性能
|
|
300
329
|
|
|
301
330
|
## License
|
|
302
331
|
|
package/dist/index.d.mts
CHANGED
|
@@ -306,11 +306,84 @@ interface ScopeProps {
|
|
|
306
306
|
*/
|
|
307
307
|
declare const Scope: FC<ScopeProps>;
|
|
308
308
|
|
|
309
|
+
interface DateRenderProps<T = string> {
|
|
310
|
+
/**
|
|
311
|
+
* @description_en The input date to render (Date object, ISO string, or timestamp).
|
|
312
|
+
* @description_zh 要渲染的输入日期(Date 对象、ISO 字符串或时间戳)。
|
|
313
|
+
*/
|
|
314
|
+
source: Date | string | number;
|
|
315
|
+
/**
|
|
316
|
+
* @description_en Function to format the date.
|
|
317
|
+
* @description_zh 格式化日期的函数。
|
|
318
|
+
* @optional
|
|
319
|
+
* @default toLocaleString
|
|
320
|
+
*/
|
|
321
|
+
format?: (date: Date) => T;
|
|
322
|
+
/**
|
|
323
|
+
* @description_en Function to render the formatted date.
|
|
324
|
+
* @description_zh 渲染格式化后日期的函数。
|
|
325
|
+
*/
|
|
326
|
+
children: (formatted: T) => React$1.ReactNode;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* @description_zh 一个声明式组件,用于格式化并渲染日期,简单易用且支持自定义格式化。
|
|
330
|
+
* @description_en A declarative component for formatting and rendering dates, simple to use with support for custom formatting.
|
|
331
|
+
* @component
|
|
332
|
+
* @template T - The type of the formatted date value
|
|
333
|
+
* @example
|
|
334
|
+
* ```tsx
|
|
335
|
+
* <DateRender source="2025-05-06">
|
|
336
|
+
* {(formatted) => <div>日期: {formatted}</div>}
|
|
337
|
+
* </DateRender>
|
|
338
|
+
* ```
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```tsx
|
|
342
|
+
* <DateRender<string>
|
|
343
|
+
* source={new Date()}
|
|
344
|
+
* format={(date) => date.toLocaleDateString("zh-CN")}
|
|
345
|
+
* >
|
|
346
|
+
* {(formatted) => <div>日期: {formatted}</div>}
|
|
347
|
+
* </DateRender>
|
|
348
|
+
* ```
|
|
349
|
+
*/
|
|
350
|
+
declare function DateRender<T = string>({ source, format, children, }: DateRenderProps<T>): React$1.JSX.Element | null;
|
|
351
|
+
|
|
309
352
|
/**
|
|
310
353
|
* @description 性能优化,替代 React.Children.forEach, 回调可以返回 false 来中断循环
|
|
311
354
|
* @description_en Replace React.Children.forEach, the callback can return false to interrupt the loop
|
|
312
355
|
*/
|
|
313
356
|
declare function childrenLoop(children: React$1.ReactNode | undefined, callback: (child: React$1.ReactNode, index: number) => boolean | void): void;
|
|
357
|
+
/**
|
|
358
|
+
* @param schema
|
|
359
|
+
* @example
|
|
360
|
+
* YY | 18 | Two-digit year
|
|
361
|
+
* YYYY | 2018 | Four-digit year
|
|
362
|
+
* M | 1-12 | The month, beginning at 1
|
|
363
|
+
* MM | 01-12 | The month, 2-digits
|
|
364
|
+
* MMM | Jan-Dec | The abbreviated month name
|
|
365
|
+
* MMMM | January-December | The full month name
|
|
366
|
+
* D | 1-31 | The day of the month
|
|
367
|
+
* DD | 01-31 | The day of the month, 2-digits
|
|
368
|
+
* d | 0-6 | The day of the week, with Sunday as 0
|
|
369
|
+
* dd | Su-Sa | The min name of the day of the week
|
|
370
|
+
* ddd | Sun-Sat | The short name of the day of the week
|
|
371
|
+
* dddd | Sunday-Saturday | The name of the day of the week
|
|
372
|
+
* H | 0-23 | The hour
|
|
373
|
+
* HH | 00-23 | The hour, 2-digits
|
|
374
|
+
* h | 1-12 | The hour, 12-hour clock
|
|
375
|
+
* hh | 01-12 | The hour, 12-hour clock, 2-digits
|
|
376
|
+
* m | 0-59 | The minute
|
|
377
|
+
* mm | 00-59 | The minute, 2-digits
|
|
378
|
+
* s | 0-59 | The second
|
|
379
|
+
* ss | 00-59 | The second, 2-digits
|
|
380
|
+
* SSS | 000-999 | The millisecond, 3-digits
|
|
381
|
+
* Z | +05:00 | The offset from UTC, ±HH:mm
|
|
382
|
+
* ZZ | +0500 | The offset from UTC, ±HHmm
|
|
383
|
+
* A | AM | PM
|
|
384
|
+
* a | am | pm
|
|
385
|
+
*/
|
|
386
|
+
declare function formatDate(schema: string, date?: Date): string;
|
|
314
387
|
|
|
315
388
|
interface UseControlledOptions<T> {
|
|
316
389
|
/**
|
|
@@ -339,5 +412,5 @@ interface UseControlledOptions<T> {
|
|
|
339
412
|
}
|
|
340
413
|
declare function useControlled<T>(options: UseControlledOptions<T>): [T, Dispatch<React.SetStateAction<T>>];
|
|
341
414
|
|
|
342
|
-
export { ArrayRender, False, If, Pipe, Scope, SizeBox, Switch, Toggle, True, When, childrenLoop, useControlled };
|
|
343
|
-
export type { ArrayRenderProps, ElseIfProps, ElseProps, FalseProps, IfProps, PipeProps, ScopeProps, SwitchCaseProps, SwitchDefaultProps, SwitchProps, ThenProps, ToggleProps, TrueProps, UseControlledOptions, WhenProps };
|
|
415
|
+
export { ArrayRender, DateRender, False, If, Pipe, Scope, SizeBox, Switch, Toggle, True, When, childrenLoop, formatDate, useControlled };
|
|
416
|
+
export type { ArrayRenderProps, DateRenderProps, ElseIfProps, ElseProps, FalseProps, IfProps, PipeProps, ScopeProps, SwitchCaseProps, SwitchDefaultProps, SwitchProps, ThenProps, ToggleProps, TrueProps, UseControlledOptions, WhenProps };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import r,{useMemo as h,useEffect as J,useState as b,Fragment as O,useCallback as H}from"react";function I(e,t){if(e===void 0)return;let n=0;if(Array.isArray(e)){for(const l of e)if(t(l,n++)===!1)break}else t(e,n)}function R(e,t){const n=t||new Date,l=n.getFullYear(),a=n.getMonth()+1,o=n.getDate(),i=n.getHours(),c=n.getMinutes(),u=n.getSeconds(),d=n.getMilliseconds(),s=n.getDay(),f=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],m=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],y=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],T=["January","February","March","April","May","June","July","August","September","October","November","December"],M=s===0?6:s-1,Y=m[M],v=f[M],D=a-1,C=T[D],A=y[D],x={YY:l.toString().slice(2),YYYY:l.toString(),M:a.toString(),MM:a.toString().padStart(2,"0"),MMM:A,MMMM:C,D:o.toString(),DD:o.toString().padStart(2,"0"),d:s.toString(),dd:v,ddd:v,dddd:Y,H:i.toString(),HH:i.toString().padStart(2,"0"),h:(i%12).toString(),hh:(i%12).toString().padStart(2,"0"),m:c.toString(),mm:c.toString().padStart(2,"0"),s:u.toString(),ss:u.toString().padStart(2,"0"),SSS:d.toString().padStart(3,"0"),Z:"+08:00",ZZ:"+0800",A:i<12?"AM":"PM",a:i<12?"am":"pm"};return e.replace(/YYYY|YY|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|m{1,2}|s{1,2}|SSS|Z{1,2}|A|a/g,k=>x[k])}const _=(e,t)=>e===t,S=e=>r.createElement(r.Fragment,null,e.children);S.displayName="Switch_Case";const E=e=>r.createElement(r.Fragment,null,e.children);E.displayName="Switch_Default";const g=e=>{const{value:t,compare:n=_,children:l,strict:a=!1}=e,o=new Set;let i=null,c=null,u=!1;return I(l,(d,s)=>{if(!r.isValidElement(d))throw new Error(`Switch Children only accepts valid React elements at index ${s}`);const f=d.type;if(f.displayName===S.displayName){const m=d.props;if(o.has(m.value))throw new Error(`Switch found duplicate Case value at index ${s}: ${JSON.stringify(m.value)}${a?" (detected in strict mode)":""}`);if(o.add(m.value),!i&&n(t,m.value)&&(i=m.children,a===!1))return!1}else if(f.displayName===E.displayName){if(u)throw new Error(`Switch can only have one Default child at index ${s}`);if(u=!0,c=d.props.children,!a&&i)return!1}else throw new Error(`Switch Children only accepts 'Case' or 'Default' elements, found: ${String(f.displayName||f.name||f)} at index ${s}`)}),r.createElement(r.Fragment,null,i??c)};g.displayName="Switch",g.Case=S,g.Default=E,g.createTyped=function(){return{Switch:g,Case:S,Default:E}};const w=e=>r.createElement(r.Fragment,null,e.children),N=({children:e})=>r.createElement(r.Fragment,null,e),F=e=>r.createElement(r.Fragment,null,e.children);w.displayName="If_Then",N.displayName="If_Else",F.displayName="If_ElseIf";const p=({condition:e,children:t})=>{let n=null,l=null;const a=[];if(r.Children.forEach(t,o=>{if(!r.isValidElement(o))throw new Error("If component only accepts valid React elements");const i=o.type;if(i.displayName===w.displayName){if(n)throw new Error("If component can only have one Then child");n=o}else if(i.displayName===F.displayName)a.push(o);else if(i.displayName===N.displayName){if(l)throw new Error("If component can only have one Else child");l=o}else throw new Error(`If component only accepts 'Then', 'ElseIf', or 'Else' elements as children, found: ${String(i.displayName||i.name||i)}`)}),e)return n?r.createElement(r.Fragment,null,n.props.children):null;for(const o of a)if(o.props.condition)return r.createElement(r.Fragment,null,o.props.children);return l?r.createElement(r.Fragment,null,l.props.children):null};p.displayName="If",p.Then=w,p.ElseIf=F,p.Else=N,p.createTyped=function(){return{If:p,Then:w,ElseIf:F,Else:N}};const B=({condition:e,children:t})=>e?r.createElement(r.Fragment,null,t):null,P=({condition:e,children:t})=>e===!1?r.createElement(r.Fragment,null,t):null,W=({all:e,any:t,none:n,children:l,fallback:a})=>h(()=>(e&&(t||n)&&console.warn('When: Multiple condition types (all, any, none) provided; "all" takes precedence.'),!!(e&&e.length>0&&e.every(Boolean)||t&&t.length>0&&t.some(Boolean)||n&&n.length>0&&n.every(o=>!o))),[e,t,n])?r.createElement(r.Fragment,null,l):r.createElement(r.Fragment,null,a||null),Z=({data:e,transform:t,render:n,fallback:l})=>{const a=h(()=>t.reduce((o,i)=>i(o),e),[e,t]);return a==null?r.createElement(r.Fragment,null,l||null):r.createElement(r.Fragment,null,n(a))},V=e=>{const{index:t=0,options:n,next:l,render:a}=e;J(()=>{if(n.length<t+1)throw new Error(`Index ${t} is out of bounds for options array of length ${n.length}. Defaulting to first option.`)},[t,n]);const[o,i]=b(t),c=()=>{i(u=>n.length?l?l(u,n):(u+1)%n.length:u)};return a(n[o],c)},$=e=>{const{children:t,h:n,w:l,size:a,height:o,width:i,className:c}=e;return r.createElement("div",{style:{width:a||l||i,height:a||n||o,flexShrink:0},className:c},t)};function j(e){const{items:t,renderItem:n,filter:l}=e;return t?r.createElement(O,null,t.map((a,o)=>l&&!l(a)?null:n(a,o))):(console.error("ArrayRender: items is null"),null)}const z=({let:e,props:t,children:n,fallback:l})=>{const a=h(()=>typeof e=="function"?e(t):e,[e,t]);return!n||!Object.keys(a).length?r.createElement(r.Fragment,null,l||null):r.createElement(r.Fragment,null,n(a))};function L({source:e,format:t,children:n}){const l=h(()=>{if(e instanceof Date)return e;if(typeof e=="string"||typeof e=="number"){const o=new Date(e);return isNaN(o.getTime())?null:o}return null},[e]),a=h(()=>l?t?t(l):l.toLocaleString():null,[l,t]);return!a||!n?null:r.createElement(r.Fragment,null,n(a))}const q="onChange",G="value";function K(e){const{defaultValue:t,onBeforeChange:n,trigger:l=q,valuePropName:a=G,props:o}=e,i=Object.prototype.hasOwnProperty.call(o,a),[c,u]=b(t),d=i?o[a]:c,s=h(()=>o[l],[o,l]),f=H(m=>{const y=typeof m=="function"?m(d):m;n&&n(y,d)===!1||(i||u(y),s&&s(y))},[i,n,l,d,s]);return[d,f]}export{j as ArrayRender,L as DateRender,P as False,p as If,Z as Pipe,z as Scope,$ as SizeBox,g as Switch,V as Toggle,B as True,W as When,I as childrenLoop,R as formatDate,K as useControlled};
|
package/package.json
CHANGED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
|
|
3
|
+
export interface DateRenderProps<T = string> {
|
|
4
|
+
/**
|
|
5
|
+
* @description_en The input date to render (Date object, ISO string, or timestamp).
|
|
6
|
+
* @description_zh 要渲染的输入日期(Date 对象、ISO 字符串或时间戳)。
|
|
7
|
+
*/
|
|
8
|
+
source: Date | string | number;
|
|
9
|
+
/**
|
|
10
|
+
* @description_en Function to format the date.
|
|
11
|
+
* @description_zh 格式化日期的函数。
|
|
12
|
+
* @optional
|
|
13
|
+
* @default toLocaleString
|
|
14
|
+
*/
|
|
15
|
+
format?: (date: Date) => T;
|
|
16
|
+
/**
|
|
17
|
+
* @description_en Function to render the formatted date.
|
|
18
|
+
* @description_zh 渲染格式化后日期的函数。
|
|
19
|
+
*/
|
|
20
|
+
children: (formatted: T) => React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @description_zh 一个声明式组件,用于格式化并渲染日期,简单易用且支持自定义格式化。
|
|
25
|
+
* @description_en A declarative component for formatting and rendering dates, simple to use with support for custom formatting.
|
|
26
|
+
* @component
|
|
27
|
+
* @template T - The type of the formatted date value
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* <DateRender source="2025-05-06">
|
|
31
|
+
* {(formatted) => <div>日期: {formatted}</div>}
|
|
32
|
+
* </DateRender>
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```tsx
|
|
37
|
+
* <DateRender<string>
|
|
38
|
+
* source={new Date()}
|
|
39
|
+
* format={(date) => date.toLocaleDateString("zh-CN")}
|
|
40
|
+
* >
|
|
41
|
+
* {(formatted) => <div>日期: {formatted}</div>}
|
|
42
|
+
* </DateRender>
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function DateRender<T = string>({
|
|
46
|
+
source,
|
|
47
|
+
format,
|
|
48
|
+
children,
|
|
49
|
+
}: DateRenderProps<T>) {
|
|
50
|
+
const date = useMemo(() => {
|
|
51
|
+
if (source instanceof Date) return source;
|
|
52
|
+
if (typeof source === "string" || typeof source === "number") {
|
|
53
|
+
const parsed = new Date(source);
|
|
54
|
+
return isNaN(parsed.getTime()) ? null : parsed;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}, [source]);
|
|
58
|
+
|
|
59
|
+
const formattedDate = useMemo(() => {
|
|
60
|
+
if (!date) return null;
|
|
61
|
+
if (format) {
|
|
62
|
+
return format(date);
|
|
63
|
+
}
|
|
64
|
+
return date.toLocaleString() as unknown as T;
|
|
65
|
+
}, [date, format]);
|
|
66
|
+
|
|
67
|
+
if (!formattedDate || !children) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return <>{children(formattedDate)}</>;
|
|
72
|
+
}
|
package/src/Common/index.ts
CHANGED
package/src/utils/index.ts
CHANGED
|
@@ -20,3 +20,122 @@ export function childrenLoop(
|
|
|
20
20
|
callback(children, index);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param schema
|
|
26
|
+
* @example
|
|
27
|
+
* YY | 18 | Two-digit year
|
|
28
|
+
* YYYY | 2018 | Four-digit year
|
|
29
|
+
* M | 1-12 | The month, beginning at 1
|
|
30
|
+
* MM | 01-12 | The month, 2-digits
|
|
31
|
+
* MMM | Jan-Dec | The abbreviated month name
|
|
32
|
+
* MMMM | January-December | The full month name
|
|
33
|
+
* D | 1-31 | The day of the month
|
|
34
|
+
* DD | 01-31 | The day of the month, 2-digits
|
|
35
|
+
* d | 0-6 | The day of the week, with Sunday as 0
|
|
36
|
+
* dd | Su-Sa | The min name of the day of the week
|
|
37
|
+
* ddd | Sun-Sat | The short name of the day of the week
|
|
38
|
+
* dddd | Sunday-Saturday | The name of the day of the week
|
|
39
|
+
* H | 0-23 | The hour
|
|
40
|
+
* HH | 00-23 | The hour, 2-digits
|
|
41
|
+
* h | 1-12 | The hour, 12-hour clock
|
|
42
|
+
* hh | 01-12 | The hour, 12-hour clock, 2-digits
|
|
43
|
+
* m | 0-59 | The minute
|
|
44
|
+
* mm | 00-59 | The minute, 2-digits
|
|
45
|
+
* s | 0-59 | The second
|
|
46
|
+
* ss | 00-59 | The second, 2-digits
|
|
47
|
+
* SSS | 000-999 | The millisecond, 3-digits
|
|
48
|
+
* Z | +05:00 | The offset from UTC, ±HH:mm
|
|
49
|
+
* ZZ | +0500 | The offset from UTC, ±HHmm
|
|
50
|
+
* A | AM | PM
|
|
51
|
+
* a | am | pm
|
|
52
|
+
*/
|
|
53
|
+
export function formatDate(schema: string, date?: Date): string {
|
|
54
|
+
const d = date || new Date();
|
|
55
|
+
const year = d.getFullYear();
|
|
56
|
+
const month = d.getMonth() + 1;
|
|
57
|
+
const day = d.getDate();
|
|
58
|
+
const hour = d.getHours();
|
|
59
|
+
const minute = d.getMinutes();
|
|
60
|
+
const second = d.getSeconds();
|
|
61
|
+
const millisecond = d.getMilliseconds();
|
|
62
|
+
const week = d.getDay();
|
|
63
|
+
const weekName = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
64
|
+
const weekFullName = [
|
|
65
|
+
"Sunday",
|
|
66
|
+
"Monday",
|
|
67
|
+
"Tuesday",
|
|
68
|
+
"Wednesday",
|
|
69
|
+
"Thursday",
|
|
70
|
+
"Friday",
|
|
71
|
+
"Saturday",
|
|
72
|
+
];
|
|
73
|
+
const monthName = [
|
|
74
|
+
"Jan",
|
|
75
|
+
"Feb",
|
|
76
|
+
"Mar",
|
|
77
|
+
"Apr",
|
|
78
|
+
"May",
|
|
79
|
+
"Jun",
|
|
80
|
+
"Jul",
|
|
81
|
+
"Aug",
|
|
82
|
+
"Sep",
|
|
83
|
+
"Oct",
|
|
84
|
+
"Nov",
|
|
85
|
+
"Dec",
|
|
86
|
+
];
|
|
87
|
+
const monthFullName = [
|
|
88
|
+
"January",
|
|
89
|
+
"February",
|
|
90
|
+
"March",
|
|
91
|
+
"April",
|
|
92
|
+
"May",
|
|
93
|
+
"June",
|
|
94
|
+
"July",
|
|
95
|
+
"August",
|
|
96
|
+
"September",
|
|
97
|
+
"October",
|
|
98
|
+
"November",
|
|
99
|
+
"December",
|
|
100
|
+
];
|
|
101
|
+
const weekIndex = week === 0 ? 6 : week - 1;
|
|
102
|
+
const weekFull = weekFullName[weekIndex]!;
|
|
103
|
+
const weekShort = weekName[weekIndex]!;
|
|
104
|
+
const monthIndex = month - 1;
|
|
105
|
+
const monthFull = monthFullName[monthIndex]!;
|
|
106
|
+
const monthShort = monthName[monthIndex]!;
|
|
107
|
+
const map: Record<string, string> = {
|
|
108
|
+
YY: year.toString().slice(2),
|
|
109
|
+
YYYY: year.toString(),
|
|
110
|
+
M: month.toString(),
|
|
111
|
+
MM: month.toString().padStart(2, "0"),
|
|
112
|
+
MMM: monthShort,
|
|
113
|
+
MMMM: monthFull,
|
|
114
|
+
D: day.toString(),
|
|
115
|
+
DD: day.toString().padStart(2, "0"),
|
|
116
|
+
d: week.toString(),
|
|
117
|
+
dd: weekShort,
|
|
118
|
+
ddd: weekShort,
|
|
119
|
+
dddd: weekFull,
|
|
120
|
+
H: hour.toString(),
|
|
121
|
+
HH: hour.toString().padStart(2, "0"),
|
|
122
|
+
h: (hour % 12).toString(),
|
|
123
|
+
hh: (hour % 12).toString().padStart(2, "0"),
|
|
124
|
+
m: minute.toString(),
|
|
125
|
+
mm: minute.toString().padStart(2, "0"),
|
|
126
|
+
s: second.toString(),
|
|
127
|
+
ss: second.toString().padStart(2, "0"),
|
|
128
|
+
SSS: millisecond.toString().padStart(3, "0"),
|
|
129
|
+
Z: "+08:00",
|
|
130
|
+
ZZ: "+0800",
|
|
131
|
+
A: hour < 12 ? "AM" : "PM",
|
|
132
|
+
a: hour < 12 ? "am" : "pm",
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
return schema.replace(
|
|
136
|
+
/YYYY|YY|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|m{1,2}|s{1,2}|SSS|Z{1,2}|A|a/g,
|
|
137
|
+
(match) => {
|
|
138
|
+
return map[match]!;
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
}
|