@servicetitan/docs-anvil-uikit-contrib 40.1.0 → 40.3.0
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/dist/code-demo.d.ts +12 -0
- package/dist/code-demo.d.ts.map +1 -0
- package/dist/code-demo.js +65 -0
- package/dist/code-demo.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/docs/intl/date-time-range.mdx +120 -0
- package/docs/intl/utilities.mdx +116 -0
- package/package.json +22 -2
- package/src/code-demo.tsx +63 -0
- package/src/global.d.ts +43 -0
- package/src/index.ts +2 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ComponentProps, ComponentType } from 'react';
|
|
2
|
+
import CodeBlock from '@theme/CodeBlock';
|
|
3
|
+
export interface CodeDemoProps {
|
|
4
|
+
example: ComponentType;
|
|
5
|
+
theme?: 'light' | 'dark';
|
|
6
|
+
srcPath?: string;
|
|
7
|
+
src?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const CodeDemo: (props: CodeDemoProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare const DemoExample: (props: CodeDemoProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare const DemoCodeBlock: (props: CodeDemoProps & Omit<ComponentProps<typeof CodeBlock>, "children">) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=code-demo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-demo.d.ts","sourceRoot":"","sources":["../src/code-demo.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAM3D,OAAO,SAAS,MAAM,kBAAkB,CAAC;AAIzC,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,QAAQ,GAAI,OAAO,aAAa,4CAiB5C,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,aAAa,4CAa/C,CAAC;AAEF,eAAO,MAAM,aAAa,GACtB,OAAO,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,SAAS,CAAC,EAAE,UAAU,CAAC,4CAU5E,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useColorMode } from '@docusaurus/theme-common';
|
|
3
|
+
import { dark, light } from '@servicetitan/anvil-themes';
|
|
4
|
+
import { AnvilProvider } from '@servicetitan/design-system';
|
|
5
|
+
import { AnvilProvider as Anvil2Provider } from '@servicetitan/anvil2';
|
|
6
|
+
import CodeBlock from '@theme/CodeBlock';
|
|
7
|
+
import Tabs from '@theme/Tabs';
|
|
8
|
+
import TabItem from '@theme/TabItem';
|
|
9
|
+
export const CodeDemo = (props)=>{
|
|
10
|
+
return /*#__PURE__*/ _jsxs(Tabs, {
|
|
11
|
+
defaultValue: "example",
|
|
12
|
+
values: [
|
|
13
|
+
{
|
|
14
|
+
label: 'Example',
|
|
15
|
+
value: 'example'
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
label: 'Source',
|
|
19
|
+
value: 'source'
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
children: [
|
|
23
|
+
/*#__PURE__*/ _jsx(TabItem, {
|
|
24
|
+
value: "example",
|
|
25
|
+
children: /*#__PURE__*/ _jsx(DemoExample, {
|
|
26
|
+
...props
|
|
27
|
+
})
|
|
28
|
+
}),
|
|
29
|
+
/*#__PURE__*/ _jsx(TabItem, {
|
|
30
|
+
value: "source",
|
|
31
|
+
children: /*#__PURE__*/ _jsx(DemoCodeBlock, {
|
|
32
|
+
...props
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
]
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
export const DemoExample = (props)=>{
|
|
39
|
+
var _props_theme;
|
|
40
|
+
const { colorMode } = useColorMode();
|
|
41
|
+
const Example = props.example;
|
|
42
|
+
const theme = (_props_theme = props.theme) !== null && _props_theme !== void 0 ? _props_theme : colorMode;
|
|
43
|
+
return /*#__PURE__*/ _jsx(AnvilProvider, {
|
|
44
|
+
theme: theme === 'dark' ? dark : light,
|
|
45
|
+
children: /*#__PURE__*/ _jsx(Anvil2Provider, {
|
|
46
|
+
themeData: {
|
|
47
|
+
mode: theme === 'dark' ? dark : light
|
|
48
|
+
},
|
|
49
|
+
children: /*#__PURE__*/ _jsx(Example, {})
|
|
50
|
+
})
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
export const DemoCodeBlock = (props)=>{
|
|
54
|
+
var _ref;
|
|
55
|
+
var _srcPath_match_groups, _srcPath_match;
|
|
56
|
+
const { srcPath, src, ...rest } = props;
|
|
57
|
+
const language = (_ref = srcPath === null || srcPath === void 0 ? void 0 : (_srcPath_match = srcPath.match(/\.(?<ext>[^\.]+)$/)) === null || _srcPath_match === void 0 ? void 0 : (_srcPath_match_groups = _srcPath_match.groups) === null || _srcPath_match_groups === void 0 ? void 0 : _srcPath_match_groups.ext) !== null && _ref !== void 0 ? _ref : 'tsx';
|
|
58
|
+
return /*#__PURE__*/ _jsx(CodeBlock, {
|
|
59
|
+
language: language,
|
|
60
|
+
...rest,
|
|
61
|
+
children: src
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=code-demo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/code-demo.tsx"],"sourcesContent":["import type { ComponentProps, ComponentType } from 'react';\nimport { useColorMode } from '@docusaurus/theme-common';\nimport { dark, light } from '@servicetitan/anvil-themes';\nimport { AnvilProvider } from '@servicetitan/design-system';\nimport { AnvilProvider as Anvil2Provider } from '@servicetitan/anvil2';\n\nimport CodeBlock from '@theme/CodeBlock';\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\nexport interface CodeDemoProps {\n example: ComponentType;\n theme?: 'light' | 'dark';\n srcPath?: string;\n src?: string;\n}\n\nexport const CodeDemo = (props: CodeDemoProps) => {\n return (\n <Tabs\n defaultValue=\"example\"\n values={[\n { label: 'Example', value: 'example' },\n { label: 'Source', value: 'source' },\n ]}\n >\n <TabItem value=\"example\">\n <DemoExample {...props} />\n </TabItem>\n <TabItem value=\"source\">\n <DemoCodeBlock {...props} />\n </TabItem>\n </Tabs>\n );\n};\n\nexport const DemoExample = (props: CodeDemoProps) => {\n const { colorMode } = useColorMode();\n const Example = props.example;\n const theme = props.theme ?? colorMode;\n\n return (\n <AnvilProvider theme={theme === 'dark' ? dark : light}>\n {/* themeData.mode expects 'light' | 'dark', but a theme object is passed here to match current behavior. */}\n <Anvil2Provider themeData={{ mode: (theme === 'dark' ? dark : light) as never }}>\n <Example />\n </Anvil2Provider>\n </AnvilProvider>\n );\n};\n\nexport const DemoCodeBlock = (\n props: CodeDemoProps & Omit<ComponentProps<typeof CodeBlock>, 'children'>\n) => {\n const { srcPath, src, ...rest } = props;\n const language = srcPath?.match(/\\.(?<ext>[^\\.]+)$/)?.groups?.ext ?? 'tsx';\n\n return (\n <CodeBlock language={language} {...rest}>\n {src}\n </CodeBlock>\n );\n};\n"],"names":["useColorMode","dark","light","AnvilProvider","Anvil2Provider","CodeBlock","Tabs","TabItem","CodeDemo","props","defaultValue","values","label","value","DemoExample","DemoCodeBlock","colorMode","Example","example","theme","themeData","mode","srcPath","src","rest","language","match","groups","ext"],"mappings":";AACA,SAASA,YAAY,QAAQ,2BAA2B;AACxD,SAASC,IAAI,EAAEC,KAAK,QAAQ,6BAA6B;AACzD,SAASC,aAAa,QAAQ,8BAA8B;AAC5D,SAASA,iBAAiBC,cAAc,QAAQ,uBAAuB;AAEvE,OAAOC,eAAe,mBAAmB;AACzC,OAAOC,UAAU,cAAc;AAC/B,OAAOC,aAAa,iBAAiB;AASrC,OAAO,MAAMC,WAAW,CAACC;IACrB,qBACI,MAACH;QACGI,cAAa;QACbC,QAAQ;YACJ;gBAAEC,OAAO;gBAAWC,OAAO;YAAU;YACrC;gBAAED,OAAO;gBAAUC,OAAO;YAAS;SACtC;;0BAED,KAACN;gBAAQM,OAAM;0BACX,cAAA,KAACC;oBAAa,GAAGL,KAAK;;;0BAE1B,KAACF;gBAAQM,OAAM;0BACX,cAAA,KAACE;oBAAe,GAAGN,KAAK;;;;;AAIxC,EAAE;AAEF,OAAO,MAAMK,cAAc,CAACL;QAGVA;IAFd,MAAM,EAAEO,SAAS,EAAE,GAAGhB;IACtB,MAAMiB,UAAUR,MAAMS,OAAO;IAC7B,MAAMC,SAAQV,eAAAA,MAAMU,KAAK,cAAXV,0BAAAA,eAAeO;IAE7B,qBACI,KAACb;QAAcgB,OAAOA,UAAU,SAASlB,OAAOC;kBAE5C,cAAA,KAACE;YAAegB,WAAW;gBAAEC,MAAOF,UAAU,SAASlB,OAAOC;YAAgB;sBAC1E,cAAA,KAACe;;;AAIjB,EAAE;AAEF,OAAO,MAAMF,gBAAgB,CACzBN;;QAGiBa,uBAAAA;IADjB,MAAM,EAAEA,OAAO,EAAEC,GAAG,EAAE,GAAGC,MAAM,GAAGf;IAClC,MAAMgB,mBAAWH,oBAAAA,+BAAAA,iBAAAA,QAASI,KAAK,CAAC,kCAAfJ,sCAAAA,wBAAAA,eAAqCK,MAAM,cAA3CL,4CAAAA,sBAA6CM,GAAG,uCAAI;IAErE,qBACI,KAACvB;QAAUoB,UAAUA;QAAW,GAAGD,IAAI;kBAClCD;;AAGb,EAAE"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type { CodeDemoProps } from './code-demo';\nexport { CodeDemo, DemoExample, DemoCodeBlock } from './code-demo';\n"],"names":["CodeDemo","DemoExample","DemoCodeBlock"],"mappings":"AACA,SAASA,QAAQ,EAAEC,WAAW,EAAEC,aAAa,QAAQ,cAAc"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Date and Time Range
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
import { FormattedDateTimeRangeMiniDemo } from '@servicetitan/intl/demo';
|
|
6
|
+
import { DemoExample } from '@site/src/components/code-demo';
|
|
7
|
+
import Tabs from '@theme/Tabs';
|
|
8
|
+
import TabItem from '@theme/TabItem';
|
|
9
|
+
|
|
10
|
+
Use `FormattedDateTimeRange` and `formatDateTimeRange` to format a date range as combined date and time. The browser's `Intl.DateTimeFormat.formatRange()` API intelligently collapses shared parts of the range (e.g., same-day ranges omit the repeated date).
|
|
11
|
+
|
|
12
|
+
## Available Formats
|
|
13
|
+
|
|
14
|
+
The following standard ServiceTitan formats are available (examples are in `en-US` locale).
|
|
15
|
+
|
|
16
|
+
| Format | Description | Example (multi-day) |
|
|
17
|
+
| :------------------ | :-------------------------------------------------------------------------- | :-------------------------------------------------------------------------- |
|
|
18
|
+
| `short` | Short date and short time. This is the default when no format is specified. | `01/09/2025, 4:00 PM – 01/10/2025, 5:00 PM` |
|
|
19
|
+
| `shortWithTimeZone` | Short date and short time, with timezone | `01/09/2025, 4:00 PM – 01/10/2025, 5:00 PM EST` |
|
|
20
|
+
| `long` | Long date and short time | `January 9, 2025 at 4:00 PM – January 10, 2025 at 5:00 PM` |
|
|
21
|
+
| `longWithTimeZone` | Long date and short time, with timezone | `January 9, 2025 at 4:00 PM – January 10, 2025 at 5:00 PM EST` |
|
|
22
|
+
|
|
23
|
+
Any options passed to `FormattedDateTimeRange` or `formatDateTimeRange` will be merged on top of `{ format: 'short' }` (which expands to `{ day: '2-digit', month: '2-digit', year: 'numeric', hour: 'numeric', minute: 'numeric' }` [Intl.DateTimeFormatOptions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options)). If you want to use your custom options only, you can pass `format: undefined` to disable the default.
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
### FormattedDateTimeRange
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import { FormattedDateTimeRange } from '@servicetitan/intl';
|
|
31
|
+
|
|
32
|
+
function DateTimeRangeExample() {
|
|
33
|
+
const startDate = new Date('2025-01-09T16:00:00-05:00');
|
|
34
|
+
const endDate = new Date('2025-01-10T17:00:00-05:00');
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<>
|
|
38
|
+
<FormattedDateTimeRange from={startDate} to={endDate} /> {/* 01/09/2025, 4:00 PM – 01/10/2025, 5:00 PM */}
|
|
39
|
+
<FormattedDateTimeRange from={startDate} to={endDate} format="short" /> {/* 01/09/2025, 4:00 PM – 01/10/2025, 5:00 PM */}
|
|
40
|
+
<FormattedDateTimeRange from={startDate} to={endDate} format="shortWithTimeZone" /> {/* 01/09/2025, 4:00 PM – 01/10/2025, 5:00 PM EST */}
|
|
41
|
+
<FormattedDateTimeRange from={startDate} to={endDate} format="long" /> {/* January 9, 2025 at 4:00 PM – January 10, 2025 at 5:00 PM */}
|
|
42
|
+
<FormattedDateTimeRange from={startDate} to={endDate} format="longWithTimeZone" /> {/* January 9, 2025 at 4:00 PM – January 10, 2025 at 5:00 PM EST */}
|
|
43
|
+
</>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### formatDateTimeRange
|
|
49
|
+
|
|
50
|
+
<Tabs
|
|
51
|
+
defaultValue="hook"
|
|
52
|
+
values={[
|
|
53
|
+
{ label: 'React Hook', value: 'hook' },
|
|
54
|
+
{ label: 'MobX Store', value: 'store'}
|
|
55
|
+
]}
|
|
56
|
+
>
|
|
57
|
+
<TabItem value="hook">
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
import { useIntl } from '@servicetitan/intl';
|
|
61
|
+
|
|
62
|
+
function DateTimeRangeExample() {
|
|
63
|
+
const { formatDateTimeRange } = useIntl();
|
|
64
|
+
const startDate = new Date('2025-01-09T16:00:00-05:00');
|
|
65
|
+
const endDate = new Date('2025-01-10T17:00:00-05:00');
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<>
|
|
69
|
+
{formatDateTimeRange(startDate, endDate)} {/* 01/09/2025, 4:00 PM – 01/10/2025, 5:00 PM */}
|
|
70
|
+
{formatDateTimeRange(startDate, endDate, { format: 'short' })} {/* 01/09/2025, 4:00 PM – 01/10/2025, 5:00 PM */}
|
|
71
|
+
{formatDateTimeRange(startDate, endDate, { format: 'shortWithTimeZone' })} {/* 01/09/2025, 4:00 PM – 01/10/2025, 5:00 PM EST */}
|
|
72
|
+
{formatDateTimeRange(startDate, endDate, { format: 'long' })} {/* January 9, 2025 at 4:00 PM – January 10, 2025 at 5:00 PM */}
|
|
73
|
+
{formatDateTimeRange(startDate, endDate, { format: 'longWithTimeZone' })} {/* January 9, 2025 at 4:00 PM – January 10, 2025 at 5:00 PM EST */}
|
|
74
|
+
</>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
</TabItem>
|
|
80
|
+
<TabItem value="store">
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
import { inject, injectable } from '@servicetitan/react-ioc';
|
|
84
|
+
import { IntlStore } from '@servicetitan/intl/mobx';
|
|
85
|
+
|
|
86
|
+
@injectable()
|
|
87
|
+
class MyStore {
|
|
88
|
+
constructor(@inject(IntlStore) private readonly intlStore: IntlStore) {}
|
|
89
|
+
|
|
90
|
+
formatDateTimeRange() {
|
|
91
|
+
const startDate = new Date('2025-01-09T16:00:00-05:00');
|
|
92
|
+
const endDate = new Date('2025-01-10T17:00:00-05:00');
|
|
93
|
+
const { formatDateTimeRange } = this.intlStore.intl;
|
|
94
|
+
return [
|
|
95
|
+
formatDateTimeRange(startDate, endDate), // 01/09/2025, 4:00 PM – 01/10/2025, 5:00 PM
|
|
96
|
+
formatDateTimeRange(startDate, endDate, { format: 'short' }), // 01/09/2025, 4:00 PM – 01/10/2025, 5:00 PM
|
|
97
|
+
formatDateTimeRange(startDate, endDate, { format: 'shortWithTimeZone' }), // 01/09/2025, 4:00 PM – 01/10/2025, 5:00 PM EST
|
|
98
|
+
formatDateTimeRange(startDate, endDate, { format: 'long' }), // January 9, 2025 at 4:00 PM – January 10, 2025 at 5:00 PM
|
|
99
|
+
formatDateTimeRange(startDate, endDate, { format: 'longWithTimeZone' }), // January 9, 2025 at 4:00 PM – January 10, 2025 at 5:00 PM EST
|
|
100
|
+
];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
</TabItem>
|
|
106
|
+
</Tabs>
|
|
107
|
+
|
|
108
|
+
### Further customization
|
|
109
|
+
|
|
110
|
+
To customize the formatting, pass `FormattedDateTimeRange` and `formatDateTimeRange` the same [options](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat#using_options) as the native `Intl.DateTimeFormat` API. For example,
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
const startDate = new Date('2025-01-09T16:00:00-05:00');
|
|
114
|
+
const endDate = new Date('2025-01-10T17:00:00-05:00');
|
|
115
|
+
formatDateTimeRange(startDate, endDate, { format: 'long', weekday: 'short' }); // Thu, January 9, 2025 at 4:00 PM – Fri, January 10, 2025 at 5:00 PM
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Demo
|
|
119
|
+
|
|
120
|
+
<DemoExample example={FormattedDateTimeRangeMiniDemo} />
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Utilities
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
import { IntlUtilsMiniDemo } from '@servicetitan/intl/demo';
|
|
6
|
+
import { DemoExample } from '@site/src/components/code-demo';
|
|
7
|
+
import Tabs from '@theme/Tabs';
|
|
8
|
+
import TabItem from '@theme/TabItem';
|
|
9
|
+
|
|
10
|
+
Timezone utility functions are available on the `intl` object. They use the configured locale and timezone automatically.
|
|
11
|
+
|
|
12
|
+
## getTzAbbreviation
|
|
13
|
+
|
|
14
|
+
Returns the timezone abbreviation (e.g., "EST", "PDT"). The result is DST-aware — passing a summer date returns the daylight saving abbreviation (e.g., "EDT" instead of "EST"). Defaults to `'short'` format. Pass any [`Intl.DateTimeFormatOptions['timeZoneName']`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#timezonename) value to customize.
|
|
15
|
+
|
|
16
|
+
### Usage
|
|
17
|
+
|
|
18
|
+
<Tabs
|
|
19
|
+
defaultValue="hook"
|
|
20
|
+
values={[
|
|
21
|
+
{ label: 'React Hook', value: 'hook' },
|
|
22
|
+
{ label: 'MobX Store', value: 'store'}
|
|
23
|
+
]}
|
|
24
|
+
>
|
|
25
|
+
<TabItem value="hook">
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { useIntl } from '@servicetitan/intl';
|
|
29
|
+
|
|
30
|
+
function TimezoneExample() {
|
|
31
|
+
const intl = useIntl();
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<>
|
|
35
|
+
{intl.getTzAbbreviation()} {/* "EST" (or "EDT" in summer) */}
|
|
36
|
+
{intl.getTzAbbreviation(new Date(), 'shortOffset')} {/* "GMT-5" */}
|
|
37
|
+
</>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
</TabItem>
|
|
43
|
+
<TabItem value="store">
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import { inject, injectable } from '@servicetitan/react-ioc';
|
|
47
|
+
import { IntlStore } from '@servicetitan/intl/mobx';
|
|
48
|
+
|
|
49
|
+
@injectable()
|
|
50
|
+
class MyStore {
|
|
51
|
+
constructor(@inject(IntlStore) private readonly intlStore: IntlStore) {}
|
|
52
|
+
|
|
53
|
+
getTimezoneLabel() {
|
|
54
|
+
const { getTzAbbreviation } = this.intlStore.intl;
|
|
55
|
+
return getTzAbbreviation(); // "EST"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
</TabItem>
|
|
61
|
+
</Tabs>
|
|
62
|
+
|
|
63
|
+
## getTzName
|
|
64
|
+
|
|
65
|
+
Returns the full timezone name (e.g., "Eastern Time", "Eastern Standard Time"). Like `getTzAbbreviation`, the result is DST-aware. Defaults to `'longGeneric'` format. Pass any [`Intl.DateTimeFormatOptions['timeZoneName']`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#timezonename) value to customize.
|
|
66
|
+
|
|
67
|
+
### Usage
|
|
68
|
+
|
|
69
|
+
<Tabs
|
|
70
|
+
defaultValue="hook"
|
|
71
|
+
values={[
|
|
72
|
+
{ label: 'React Hook', value: 'hook' },
|
|
73
|
+
{ label: 'MobX Store', value: 'store'}
|
|
74
|
+
]}
|
|
75
|
+
>
|
|
76
|
+
<TabItem value="hook">
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
import { useIntl } from '@servicetitan/intl';
|
|
80
|
+
|
|
81
|
+
function TimezoneExample() {
|
|
82
|
+
const intl = useIntl();
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<>
|
|
86
|
+
{intl.getTzName()} {/* "Eastern Time" */}
|
|
87
|
+
{intl.getTzName(new Date(), 'long')} {/* "Eastern Standard Time" */}
|
|
88
|
+
</>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
</TabItem>
|
|
94
|
+
<TabItem value="store">
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import { inject, injectable } from '@servicetitan/react-ioc';
|
|
98
|
+
import { IntlStore } from '@servicetitan/intl/mobx';
|
|
99
|
+
|
|
100
|
+
@injectable()
|
|
101
|
+
class MyStore {
|
|
102
|
+
constructor(@inject(IntlStore) private readonly intlStore: IntlStore) {}
|
|
103
|
+
|
|
104
|
+
getTimezoneName() {
|
|
105
|
+
const { getTzName } = this.intlStore.intl;
|
|
106
|
+
return getTzName(); // "Eastern Time"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
</TabItem>
|
|
112
|
+
</Tabs>
|
|
113
|
+
|
|
114
|
+
## Demo
|
|
115
|
+
|
|
116
|
+
<DemoExample example={IntlUtilsMiniDemo} />
|
package/package.json
CHANGED
|
@@ -1,21 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/docs-anvil-uikit-contrib",
|
|
3
|
-
"version": "40.
|
|
3
|
+
"version": "40.3.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/servicetitan/anvil-uikit-contrib.git",
|
|
8
8
|
"directory": "docusaurus"
|
|
9
9
|
},
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"typings": "./dist/index.d.ts",
|
|
12
|
+
"sideEffects": false,
|
|
10
13
|
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"src",
|
|
11
16
|
"docs",
|
|
12
17
|
"remark"
|
|
13
18
|
],
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@docusaurus/theme-common": "^3.10.1",
|
|
21
|
+
"@servicetitan/anvil-themes": "^14.5.3",
|
|
22
|
+
"@servicetitan/anvil2": "^3.4.2",
|
|
23
|
+
"@servicetitan/design-system": "~14.5.1",
|
|
24
|
+
"@types/react": "~18.2.55",
|
|
25
|
+
"react": "^18.2.0"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@docusaurus/theme-common": ">=3.0.0",
|
|
29
|
+
"@servicetitan/anvil-themes": ">=13.2.1",
|
|
30
|
+
"@servicetitan/anvil2": ">=3.0.0",
|
|
31
|
+
"@servicetitan/design-system": ">=13.2.1",
|
|
32
|
+
"react": ">=17.0.2"
|
|
33
|
+
},
|
|
14
34
|
"publishConfig": {
|
|
15
35
|
"access": "public"
|
|
16
36
|
},
|
|
17
37
|
"cli": {
|
|
18
38
|
"webpack": false
|
|
19
39
|
},
|
|
20
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "da17654a172fa74e9168b5b15a81049108158db9"
|
|
21
41
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ComponentProps, ComponentType } from 'react';
|
|
2
|
+
import { useColorMode } from '@docusaurus/theme-common';
|
|
3
|
+
import { dark, light } from '@servicetitan/anvil-themes';
|
|
4
|
+
import { AnvilProvider } from '@servicetitan/design-system';
|
|
5
|
+
import { AnvilProvider as Anvil2Provider } from '@servicetitan/anvil2';
|
|
6
|
+
|
|
7
|
+
import CodeBlock from '@theme/CodeBlock';
|
|
8
|
+
import Tabs from '@theme/Tabs';
|
|
9
|
+
import TabItem from '@theme/TabItem';
|
|
10
|
+
|
|
11
|
+
export interface CodeDemoProps {
|
|
12
|
+
example: ComponentType;
|
|
13
|
+
theme?: 'light' | 'dark';
|
|
14
|
+
srcPath?: string;
|
|
15
|
+
src?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const CodeDemo = (props: CodeDemoProps) => {
|
|
19
|
+
return (
|
|
20
|
+
<Tabs
|
|
21
|
+
defaultValue="example"
|
|
22
|
+
values={[
|
|
23
|
+
{ label: 'Example', value: 'example' },
|
|
24
|
+
{ label: 'Source', value: 'source' },
|
|
25
|
+
]}
|
|
26
|
+
>
|
|
27
|
+
<TabItem value="example">
|
|
28
|
+
<DemoExample {...props} />
|
|
29
|
+
</TabItem>
|
|
30
|
+
<TabItem value="source">
|
|
31
|
+
<DemoCodeBlock {...props} />
|
|
32
|
+
</TabItem>
|
|
33
|
+
</Tabs>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const DemoExample = (props: CodeDemoProps) => {
|
|
38
|
+
const { colorMode } = useColorMode();
|
|
39
|
+
const Example = props.example;
|
|
40
|
+
const theme = props.theme ?? colorMode;
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<AnvilProvider theme={theme === 'dark' ? dark : light}>
|
|
44
|
+
{/* themeData.mode expects 'light' | 'dark', but a theme object is passed here to match current behavior. */}
|
|
45
|
+
<Anvil2Provider themeData={{ mode: (theme === 'dark' ? dark : light) as never }}>
|
|
46
|
+
<Example />
|
|
47
|
+
</Anvil2Provider>
|
|
48
|
+
</AnvilProvider>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const DemoCodeBlock = (
|
|
53
|
+
props: CodeDemoProps & Omit<ComponentProps<typeof CodeBlock>, 'children'>
|
|
54
|
+
) => {
|
|
55
|
+
const { srcPath, src, ...rest } = props;
|
|
56
|
+
const language = srcPath?.match(/\.(?<ext>[^\.]+)$/)?.groups?.ext ?? 'tsx';
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<CodeBlock language={language} {...rest}>
|
|
60
|
+
{src}
|
|
61
|
+
</CodeBlock>
|
|
62
|
+
);
|
|
63
|
+
};
|
package/src/global.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* `@theme/*` resolves via a webpack alias, not a real package, so types are
|
|
3
|
+
* copied here rather than bloating this project with Docusaurus's themes.
|
|
4
|
+
* Copied from src/theme-classic.d.ts in @docusaurus/theme-classic@3.10.1
|
|
5
|
+
*/
|
|
6
|
+
/* eslint-disable import/no-default-export */
|
|
7
|
+
declare module '@theme/CodeBlock' {
|
|
8
|
+
import type { ReactNode } from 'react';
|
|
9
|
+
|
|
10
|
+
export interface Props {
|
|
11
|
+
readonly children: ReactNode;
|
|
12
|
+
readonly className?: string;
|
|
13
|
+
readonly metastring?: string;
|
|
14
|
+
readonly title?: ReactNode;
|
|
15
|
+
readonly language?: string;
|
|
16
|
+
readonly showLineNumbers?: boolean | number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default function CodeBlock(props: Props): ReactNode;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
declare module '@theme/Tabs' {
|
|
23
|
+
import type { ReactNode } from 'react';
|
|
24
|
+
|
|
25
|
+
export interface Props {
|
|
26
|
+
readonly children: ReactNode;
|
|
27
|
+
readonly defaultValue?: string;
|
|
28
|
+
readonly values?: readonly { value: string; label?: string }[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default function Tabs(props: Props): ReactNode;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
declare module '@theme/TabItem' {
|
|
35
|
+
import type { ReactNode } from 'react';
|
|
36
|
+
|
|
37
|
+
export interface Props {
|
|
38
|
+
readonly children: ReactNode;
|
|
39
|
+
readonly value: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default function TabItem(props: Props): ReactNode;
|
|
43
|
+
}
|
package/src/index.ts
ADDED