playbook_ui 12.32.0 → 12.33.0.pre.alpha.revert2650closedialogonoutsideclick977

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/index.js +1 -1
  3. data/app/pb_kits/playbook/pb_background/_background.tsx +10 -1
  4. data/app/pb_kits/playbook/pb_background/background.html.erb +2 -1
  5. data/app/pb_kits/playbook/pb_background/background.rb +4 -2
  6. data/app/pb_kits/playbook/pb_body/_body_mixins.scss +1 -0
  7. data/app/pb_kits/playbook/pb_button/_button_mixins.scss +6 -6
  8. data/app/pb_kits/playbook/pb_circle_icon_button/_circle_icon_button.scss +1 -1
  9. data/app/pb_kits/playbook/pb_date/_date.tsx +7 -8
  10. data/app/pb_kits/playbook/pb_date/docs/_date_alignment.jsx +2 -2
  11. data/app/pb_kits/playbook/pb_date/docs/_date_default.jsx +4 -4
  12. data/app/pb_kits/playbook/pb_date/docs/_date_unstyled.jsx +2 -2
  13. data/app/pb_kits/playbook/pb_date/docs/_date_variants.jsx +5 -5
  14. data/app/pb_kits/playbook/pb_date_range_inline/_date_range_inline.tsx +45 -31
  15. data/app/pb_kits/playbook/pb_date_range_stacked/_date_range_stacked.tsx +5 -3
  16. data/app/pb_kits/playbook/pb_date_stacked/_date_stacked.tsx +24 -21
  17. data/app/pb_kits/playbook/pb_date_time/_date_time.tsx +1 -1
  18. data/app/pb_kits/playbook/pb_date_time/dateTime.test.js +1 -1
  19. data/app/pb_kits/playbook/pb_date_time_stacked/_date_time_stacked.tsx +2 -2
  20. data/app/pb_kits/playbook/pb_date_time_stacked/date_time_stacked.test.js +1 -1
  21. data/app/pb_kits/playbook/pb_date_year_stacked/_date_year_stacked.tsx +6 -8
  22. data/app/pb_kits/playbook/pb_dialog/_dialog.scss +321 -316
  23. data/app/pb_kits/playbook/pb_dialog/_dialog.tsx +12 -9
  24. data/app/pb_kits/playbook/pb_dialog/dialog.html.erb +8 -8
  25. data/app/pb_kits/playbook/pb_icon/_icon.tsx +4 -2
  26. data/app/pb_kits/playbook/pb_icon/docs/_icon_fa_kit.html.erb +1 -0
  27. data/app/pb_kits/playbook/pb_icon/docs/_icon_fa_kit.jsx +21 -0
  28. data/app/pb_kits/playbook/pb_icon/docs/_icon_fa_kit.md +7 -0
  29. data/app/pb_kits/playbook/pb_icon/docs/example.yml +2 -0
  30. data/app/pb_kits/playbook/pb_icon/docs/index.js +1 -0
  31. data/app/pb_kits/playbook/pb_icon/icon.rb +1 -1
  32. data/app/pb_kits/playbook/pb_icon_circle/_icon_circle.tsx +14 -4
  33. data/app/pb_kits/playbook/pb_icon_circle/icon_circle.rb +1 -1
  34. data/app/pb_kits/playbook/pb_icon_stat_value/_icon_stat_value.tsx +12 -1
  35. data/app/pb_kits/playbook/pb_icon_stat_value/docs/_icon_stat_value_color.html.erb +6 -0
  36. data/app/pb_kits/playbook/pb_icon_stat_value/docs/_icon_stat_value_color.jsx +9 -0
  37. data/app/pb_kits/playbook/pb_icon_stat_value/icon_stat_value.html.erb +16 -12
  38. data/app/pb_kits/playbook/pb_icon_stat_value/icon_stat_value.rb +2 -2
  39. data/app/pb_kits/playbook/pb_kit/dateTime.ts +139 -67
  40. data/app/pb_kits/playbook/pb_label_value/_label_value.tsx +52 -31
  41. data/app/pb_kits/playbook/pb_map/_map.scss +4 -0
  42. data/app/pb_kits/playbook/pb_message/_message.tsx +24 -24
  43. data/app/pb_kits/playbook/pb_time/_time.tsx +9 -11
  44. data/app/pb_kits/playbook/pb_time_range_inline/_time_range_inline.tsx +46 -49
  45. data/app/pb_kits/playbook/pb_time_stacked/_time_stacked.tsx +4 -6
  46. data/app/pb_kits/playbook/pb_timestamp/_timestamp.tsx +11 -11
  47. data/app/pb_kits/playbook/pb_weekday_stacked/_weekday_stacked.tsx +8 -11
  48. data/app/pb_kits/playbook/tokens/_colors.scss +4 -2
  49. data/app/pb_kits/playbook/utilities/_border_radius.scss +11 -1
  50. data/app/pb_kits/playbook/utilities/_line_height.scss +1 -2
  51. data/app/pb_kits/playbook/utilities/_shadow.scss +0 -1
  52. data/app/pb_kits/playbook/utilities/globalProps.ts +1 -1
  53. data/dist/playbook-rails.js +7 -7
  54. data/lib/playbook/version.rb +2 -2
  55. metadata +10 -8
  56. data/app/pb_kits/playbook/pb_logistic/_logistic.jsx +0 -120
@@ -181,7 +181,10 @@ const Dialog = (props: DialogProps) => {
181
181
  {title && !status ? <Dialog.Header>{title}</Dialog.Header> : null}
182
182
  {!status && text ? <Dialog.Body>{text}</Dialog.Body> : null}
183
183
  {status && (
184
- <Dialog.Body padding="md">
184
+ <Dialog.Body
185
+ className="dialog_status_text_align"
186
+ padding="md"
187
+ >
185
188
  <Flex align="center" orientation="column">
186
189
  <IconCircle
187
190
  icon={sweetAlertStatus[status].icon}
@@ -197,17 +200,17 @@ const Dialog = (props: DialogProps) => {
197
200
  )}
198
201
  {cancelButton && confirmButton ? (
199
202
  <Dialog.Footer>
200
- <Button
201
- loading={loading}
202
- onClick={onConfirm}
203
- htmlType="button"
203
+ <Button
204
+ loading={loading}
205
+ onClick={onConfirm}
206
+ htmlType="button"
204
207
  variant="primary">
205
208
  {confirmButton}
206
209
  </Button>
207
- <Button
208
- id="cancel-button"
209
- onClick={onCancel}
210
- variant="link"
210
+ <Button
211
+ id="cancel-button"
212
+ onClick={onCancel}
213
+ variant="link"
211
214
  htmlType="button">
212
215
  {cancelButton}
213
216
  </Button>
@@ -5,38 +5,38 @@
5
5
  id: object.id,
6
6
  class: object.classname) do %>
7
7
  <% if object.status === "" && object.title %>
8
- <%= pb_rails("dialog/dialog_header", props: {title: object.title, id: object.id }) %>
8
+ <%= pb_rails("dialog/dialog_header", props: { title: object.title, id: object.id }) %>
9
9
  <% end %>
10
10
  <% if object.status === "" && object.text %>
11
11
  <%= pb_rails("dialog/dialog_body", props: { text: object.text }) %>
12
12
  <% end %>
13
13
  <% if object.status != "" %>
14
- <%= pb_rails("dialog/dialog_body", props: {padding: "md"}) do %>
15
- <%= pb_rails("flex", props: {align: "center", orientation: "column"}) do %>
14
+ <%= pb_rails("dialog/dialog_body", props: { classname: "dialog_status_text_align" ,padding: "md" }) do %>
15
+ <%= pb_rails("flex", props: { align: "center", orientation: "column" }) do %>
16
16
  <%= pb_rails("icon_circle", props: {
17
17
  icon: object.status_alerts[0],
18
18
  variant: object.status_alerts[1],
19
19
  size: "lg"
20
20
  }) %>
21
21
  <%= pb_rails("title", props: { text: object.title, tag: "h1", size: 3, margin_top: "sm" }) %>
22
- <%= pb_rails("body", props: {text: object.text, margin_top: "sm"}) %>
22
+ <%= pb_rails("body", props: { text: object.text, margin_top: "sm" }) %>
23
23
  <% end %>
24
24
  <% end %>
25
25
  <% end %>
26
26
  <% if object.cancel_button && object.confirm_button %>
27
27
  <%= pb_rails("dialog/dialog_footer", props: {
28
- cancel_button: object.cancel_button,
28
+ cancel_button: object.cancel_button,
29
29
  confirm_button: object.confirm_button,
30
30
  id: object.id
31
31
  }) %>
32
32
  <% end %>
33
-
33
+
34
34
  <%= content %>
35
35
  <% end %>
36
36
  </div>
37
37
 
38
38
  <%= javascript_tag do %>
39
- window.addEventListener("DOMContentLoaded", () => {
39
+ window.addEventListener("DOMContentLoaded", () => {
40
40
  dialogHelper()
41
41
  })
42
- <% end %>
42
+ <% end %>
@@ -34,7 +34,7 @@ type IconProps = {
34
34
  pulse?: boolean,
35
35
  rotation?: 90 | 180 | 270,
36
36
  size?: IconSizes,
37
- fontStyle?: 'far' | 'fas' | 'fab',
37
+ fontStyle?: 'far' | 'fas' | 'fab' | 'fak',
38
38
  spin?: boolean,
39
39
  } & GlobalProps
40
40
 
@@ -76,6 +76,7 @@ const Icon = (props: IconProps) => {
76
76
  [`fa-${size}`]: size,
77
77
  [`fa-pull-${pull}`]: pull,
78
78
  [`fa-rotate-${rotation}`]: rotation,
79
+
79
80
  }
80
81
 
81
82
  // Lets check and see if the icon prop is referring to a custom Power icon...
@@ -83,7 +84,7 @@ const Icon = (props: IconProps) => {
83
84
  // this ensures the JS will not do any further operations
84
85
  // faClasses[`fa-${icon}`] = customIcon ? 'custom' : icon
85
86
  if (!customIcon) faClasses[`fa-${icon}`] = icon
86
-
87
+
87
88
  const classes = classnames(
88
89
  flipMap[flip],
89
90
  'pb_icon_kit',
@@ -110,6 +111,7 @@ const Icon = (props: IconProps) => {
110
111
  return emojiRegex.test(emoji);
111
112
  };
112
113
 
114
+
113
115
  // Add a conditional here to show only the SVG if custom
114
116
  const displaySVG = (customIcon: any) => {
115
117
  if (customIcon)
@@ -0,0 +1 @@
1
+ <%= pb_rails("icon", props: { icon: "powergon", font_style: "fak", fixed_width: true, size: "5x" }) %>
@@ -0,0 +1,21 @@
1
+ import React from 'react'
2
+
3
+ import Icon from '../_icon'
4
+
5
+ import '../../../../../../playbook-website/app/javascript/scripts/custom-icons'
6
+
7
+ const IconFaKit = (props) => {
8
+ return (
9
+ <div>
10
+ <Icon
11
+ {...props}
12
+ fixedWidth
13
+ fontStyle="fak"
14
+ icon="powergon"
15
+ size="5x"
16
+ />
17
+ </div>
18
+ )
19
+ }
20
+
21
+ export default IconFaKit
@@ -0,0 +1,7 @@
1
+ Our Icon kit allows integration with [FontAwesome's custom kit](https://fontawesome.com/v6/docs/web/setup/use-kit#contentHeader) functionality out-of-the-box.
2
+
3
+ All you need to do is 3 things:
4
+ 1) Import your custom-icon.js file as outlined in the FontAwesome docs.
5
+ 2) Use our fontStyle prop called "fak" so that our Icon component knows you are using a "fa-kit" icon.
6
+ 3) Pass in your FaKit name as a string to our icon prop (This is the name that you designated when you uploaded the icon on their site).
7
+
@@ -8,6 +8,7 @@ examples:
8
8
  - icon_border: Icon Border
9
9
  - icon_sizes: Icon Sizes
10
10
  - icon_custom: Icon Custom
11
+ - icon_fa_kit: Icon with FontAwesome Kit
11
12
 
12
13
  react:
13
14
  - icon_default: Icon Default
@@ -18,3 +19,4 @@ examples:
18
19
  - icon_border: Icon Border
19
20
  - icon_sizes: Icon Sizes
20
21
  - icon_custom: Icon Custom
22
+ - icon_fa_kit: Icon with FontAwesome Kit
@@ -6,3 +6,4 @@ export { default as IconPull } from './_icon_pull.jsx'
6
6
  export { default as IconBorder } from './_icon_border.jsx'
7
7
  export { default as IconSizes } from './_icon_sizes.jsx'
8
8
  export { default as IconCustom } from './_icon_custom.jsx'
9
+ export { default as IconFaKit} from './_icon_fa_kit.jsx'
@@ -33,7 +33,7 @@ module Playbook
33
33
  values: ["lg", "xs", "sm", "1x", "2x", "3x", "4x", "5x", "6x", "7x", "8x", "9x", "10x", nil],
34
34
  default: nil
35
35
  prop :font_style, type: Playbook::Props::Enum,
36
- values: %w[far fas fab],
36
+ values: %w[far fas fab fak],
37
37
  default: "far"
38
38
  prop :spin, type: Playbook::Props::Boolean,
39
39
  default: false
@@ -22,11 +22,21 @@ type IconCircleProps = {
22
22
  | "teal"
23
23
  | "red"
24
24
  | "yellow"
25
+ | "orange"
25
26
  | "green",
26
27
  }
27
28
 
28
29
  const IconCircle = (props: IconCircleProps) => {
29
- const { aria = {}, className, dark = false, data = {}, icon, id, size = 'md', variant = 'default' } = props
30
+ const {
31
+ aria = {},
32
+ className,
33
+ dark = false,
34
+ data = {},
35
+ icon,
36
+ id,
37
+ size = 'md',
38
+ variant = 'default'
39
+ } = props
30
40
 
31
41
  const ariaProps = buildAriaProps(aria)
32
42
  const dataProps = buildDataProps(data)
@@ -41,10 +51,10 @@ const IconCircle = (props: IconCircleProps) => {
41
51
  id={id}
42
52
  >
43
53
  <Icon
44
- dark={dark}
45
- icon={icon}
54
+ dark={dark}
55
+ icon={icon}
46
56
  />
47
-
57
+
48
58
  </div>
49
59
  )
50
60
  }
@@ -10,7 +10,7 @@ module Playbook
10
10
  values: %w[xs sm md base lg xl],
11
11
  default: "md"
12
12
  prop :variant, type: Playbook::Props::Enum,
13
- values: %w[default royal blue orange purple teal red yellow green],
13
+ values: %w[default royal blue orange purple teal red yellow green orange],
14
14
  default: "default"
15
15
 
16
16
  def classname
@@ -14,6 +14,7 @@ type IconStatValueProps = {
14
14
  aria?: { [key: string]: string },
15
15
  className?: string,
16
16
  data?: object,
17
+ dark?: boolean,
17
18
  icon: string,
18
19
  id?: string,
19
20
  orientation?: "vertical" | "horizontal",
@@ -28,6 +29,7 @@ type IconStatValueProps = {
28
29
  | "teal"
29
30
  | "red"
30
31
  | "yellow"
32
+ | "orange"
31
33
  | "green",
32
34
  }
33
35
 
@@ -36,6 +38,7 @@ const IconStatValue = (props: IconStatValueProps) => {
36
38
  aria = {},
37
39
  className,
38
40
  data = {},
41
+ dark = false,
39
42
  icon,
40
43
  id,
41
44
  orientation = 'horizontal',
@@ -55,6 +58,7 @@ const IconStatValue = (props: IconStatValueProps) => {
55
58
  if (size == 'lg') {
56
59
  return (
57
60
  <Title
61
+ dark={dark}
58
62
  size={1}
59
63
  tag="span"
60
64
  text={`${value}`}
@@ -63,6 +67,7 @@ const IconStatValue = (props: IconStatValueProps) => {
63
67
  } else if (size == 'md') {
64
68
  return (
65
69
  <Title
70
+ dark={dark}
66
71
  size={2}
67
72
  tag="span"
68
73
  text={`${value}`}
@@ -71,6 +76,7 @@ const IconStatValue = (props: IconStatValueProps) => {
71
76
  } else {
72
77
  return (
73
78
  <Title
79
+ dark={dark}
74
80
  size={3}
75
81
  tag="span"
76
82
  text={`${value}`}
@@ -87,6 +93,7 @@ const IconStatValue = (props: IconStatValueProps) => {
87
93
  id={id}
88
94
  >
89
95
  <IconCircle
96
+ dark={dark}
90
97
  icon={icon}
91
98
  size={size}
92
99
  variant={variant}
@@ -99,10 +106,14 @@ const IconStatValue = (props: IconStatValueProps) => {
99
106
  {titleSize(size)}
100
107
  &nbsp;
101
108
  <Body
109
+ dark={dark}
102
110
  text={unit}
103
111
  />
104
112
  </Flex>
105
- <Caption text={text} />
113
+ <Caption
114
+ dark={dark}
115
+ text={text}
116
+ />
106
117
  </div>
107
118
 
108
119
  </div>
@@ -46,4 +46,10 @@
46
46
  unit: "AU",
47
47
  value: 19.18,
48
48
  variant:"green"
49
+ }) %>
50
+ <%= pb_rails("icon_stat_value", props: { icon: "globe",
51
+ text: "Uranus",
52
+ unit: "AU",
53
+ value: 19.18,
54
+ variant:"orange"
49
55
  }) %>
@@ -66,6 +66,15 @@ const IconStatValueColor = (props) => {
66
66
  variant="green"
67
67
  {...props}
68
68
  />
69
+ <br />
70
+ <IconStatValue
71
+ icon="globe"
72
+ text="Uranus"
73
+ unit="AU"
74
+ value={19.18}
75
+ variant="orange"
76
+ {...props}
77
+ />
69
78
  </div>
70
79
 
71
80
  )
@@ -4,22 +4,26 @@
4
4
  data: object.data,
5
5
  class: object.classname) do %>
6
6
 
7
- <%= pb_rails "icon_circle", props: {
8
- icon: object.icon,
9
- size: object.size,
10
- variant: object.variant } %>
7
+ <%= pb_rails("icon_circle", props: {
8
+ dark: object.dark,
9
+ icon: object.icon,
10
+ size: object.size,
11
+ variant: object.variant }) %>
11
12
 
12
- <div>
13
+ <div>
13
14
  <%= pb_rails("flex", props: { align: "baseline" }) do %>
14
- <%= pb_rails "title", props: {
15
+ <%= pb_rails("title", props: {
16
+ dark: object.dark,
15
17
  tag: "span",
16
18
  text: object.value_string,
17
- size: object.title_size } %>
19
+ size: object.title_size }) %>
18
20
  &nbsp;
19
- <%= pb_rails "body", props: {
20
- text: object.unit } %>
21
+ <%= pb_rails("body", props: {
22
+ dark: object.dark,
23
+ text: object.unit }) %>
21
24
  <% end %>
22
- <%= pb_rails "caption", props: {
23
- text: object.text } %>
24
- </div>
25
+ <%= pb_rails("caption", props: {
26
+ dark: object.dark,
27
+ text: object.text }) %>
28
+ </div>
25
29
  <% end %>
@@ -9,7 +9,7 @@ module Playbook
9
9
  values: %w[sm md lg],
10
10
  default: "sm"
11
11
  prop :variant, type: Playbook::Props::Enum,
12
- values: %w[default royal blue purple teal red yellow green],
12
+ values: %w[default royal blue purple teal red yellow green orange],
13
13
  default: "default"
14
14
 
15
15
  prop :orientation, type: Playbook::Props::Enum,
@@ -22,7 +22,7 @@ module Playbook
22
22
  prop :text, type: Playbook::Props::String,
23
23
  default: ""
24
24
 
25
- prop :value, type: Playbook::Props::Numeric
25
+ prop :value
26
26
 
27
27
  def classname
28
28
  generate_classname("pb_icon_stat_value_kit", orientation, size, variant)
@@ -1,90 +1,162 @@
1
-
2
- import moment, { Moment } from 'moment'
3
- import 'moment-strftime'
4
- import 'moment-timezone'
5
-
6
- type DateTimeType = {
7
- value: string | Date,
8
- zone?: string,
9
- }
10
-
11
1
  const ABBR_DAYS = ['SU', 'M', 'T', 'W', 'TH', 'F', 'S']
12
2
 
13
- export default class DateTime {
14
- value: Moment & any
15
- constructor({ value, zone = 'America/New_York' }: DateTimeType) {
16
- this.value = this.convertToTimestampZone(value, zone)
17
- }
18
-
19
- convertToTimestampZone(value: string | Date, zone: string) {
20
- return moment(value).tz(zone)
21
- }
22
-
23
- convertToTimezone() {
24
- return this.value.strftime('%Z')
25
- }
3
+ const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
26
4
 
27
- toCustomFormat(format = '%-m/%-d') {
28
- return this.value.strftime(format)
29
- }
5
+ const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
30
6
 
31
- toYear() {
32
- return this.value.strftime('%Y')
7
+ export const toMinute = (newDate: Date | string, timeZone?: string): string => {
8
+ const date = new Date(newDate)
9
+ if (timeZone) {
10
+ return date.toLocaleTimeString(undefined, {timeZone, hour: "2-digit", minute: "2-digit"}).slice(3, 5);
11
+ } else {
12
+ return date.toLocaleTimeString(undefined, {hour: "2-digit", minute: "2-digit"}).slice(3, 5);
33
13
  }
14
+ }
34
15
 
35
- toMonth() {
36
- return this.value.strftime('%b')
16
+ export const toHour = (newDate: Date | string, timeZone?: string): string => {
17
+ const date = new Date(newDate)
18
+ if (timeZone) {
19
+ return date.toLocaleTimeString(undefined, {timeZone, hour: "numeric"}).split(' ')[0];
20
+ } else {
21
+ return date.toLocaleTimeString(undefined, {hour: "numeric"}).split(' ')[0];
37
22
  }
23
+ }
38
24
 
39
- toMonthNum() {
40
- return this.value.strftime('%-m')
41
- }
25
+ export const toDay = (newDate: Date | string, timeZone?: string): number => {
26
+ if (timeZone) {
27
+ const date = new Date(newDate.toLocaleString(undefined, { timeZone }));
28
+ return date.getDate()
29
+ } else {
30
+ const date = new Date(newDate)
31
+ return date.getDate()
32
+ }
33
+ }
42
34
 
43
- toMonthFull() {
44
- return this.value.strftime('%B')
45
- }
35
+ export const toDayAbbr = (newDate: Date | string): string => {
36
+ const date = new Date(newDate)
37
+ return ABBR_DAYS[date.getUTCDay()]
38
+ }
46
39
 
47
- toDay() {
48
- return this.value.strftime('%e')
49
- }
40
+ export const toWeekday = (newDate: Date | string): string => {
41
+ const date = new Date(newDate)
42
+ return days[date.getUTCDay()]
43
+ }
50
44
 
51
- toDayAbbr() {
52
- return ABBR_DAYS[this.value.day()]
53
- }
45
+ export const toMonth = (newDate: Date | string, timeZone?: string): string => {
46
+ if (timeZone) {
47
+ const date = new Date(newDate.toLocaleString(undefined, { timeZone }));
48
+ return months[date.getUTCMonth()]
49
+ } else {
50
+ const date = new Date(newDate)
51
+ return months[date.getUTCMonth()]
52
+ }
53
+ }
54
54
 
55
- toWeekday() {
56
- return this.value.strftime('%a')
57
- }
55
+ export const toMonthNum = (newDate: Date | string): number => {
56
+ const date = new Date(newDate)
57
+ return date.getUTCMonth() +1
58
+ }
58
59
 
59
- toHour() {
60
- return this.value.strftime('%l')
61
- }
60
+ export const toYear = (newDate: Date | string, timeZone?: string): number => {
61
+ if (timeZone) {
62
+ const date = new Date(newDate.toLocaleString(undefined, { timeZone }));
63
+ return date.getUTCFullYear()
64
+ } else {
65
+ const date = new Date(newDate)
66
+ return date.getUTCFullYear()
67
+ }
68
+ }
62
69
 
63
- toMinute() {
64
- return this.value.strftime('%M')
70
+ export const toTime = (newDate: Date | string, timeZone?: string): string => {
71
+ const date = new Date(newDate)
72
+ if (timeZone) {
73
+ return date.toLocaleTimeString(undefined, {timeZone, timeStyle: "short"}).split(' ')[0];
74
+ } else {
75
+ return date.toLocaleTimeString(undefined, {timeStyle: "short"}).split(' ')[0];
65
76
  }
77
+ }
66
78
 
67
- toMeridian() {
68
- return this.value.strftime('%P')[0]
69
- }
79
+ export const toMeridiem = (newDate: Date | string, timeZone?: string): string => {
80
+ const date = new Date(newDate)
81
+ if (timeZone) {
82
+ return date.toLocaleString(undefined, {timeZone, hour12: true }).slice(-2).charAt(0).toLocaleLowerCase();
83
+ } else {
84
+ return date.toLocaleString(undefined, {hour12: true }).slice(-2).charAt(0).toLocaleLowerCase();
85
+ }
86
+ }
70
87
 
71
- toIso() {
72
- return this.value.toISOString()
73
- }
88
+ export const toTimeZone = (newDate: Date | string, timeZone?: string): string => {
89
+ const date = new Date(newDate)
90
+ if (timeZone) {
91
+ return date.toLocaleString(undefined, {timeZone, timeZoneName: "short"}).split(' ')[3];
92
+ } else {
93
+ return date.toLocaleString(undefined, {timeZoneName: "short"}).split(' ')[3];
94
+ }
95
+ }
74
96
 
75
- toTime() {
76
- const time = this.value.strftime('%I:%M')
97
+ export const toTimeWithMeridiem = (newDate: Date | string, timeZone: string): string => {
98
+ const date = new Date(newDate)
99
+ return `${toTime(date, timeZone)}${toMeridiem(date, timeZone)}`;
100
+ }
77
101
 
78
- // strftime adds a leading 0 on single hour times. ie 08:31.
79
- // this removes that 0 to match the rails kit.
80
- return time.charAt() === '0' ? time.slice(1) : time
81
- }
102
+ export const toIso = (newDate: Date | string): string => {
103
+ const date = new Date(newDate)
104
+ return date.toISOString()
105
+ }
82
106
 
83
- toTimezone() {
84
- return this.value.strftime('%Z')
85
- }
107
+ export const fromNow = (newDate: Date | string): string => {
108
+
109
+ const startDate = new Date(newDate).getTime()
110
+ const endDate = new Date().getTime()
111
+ const elapsedTime = endDate - startDate
112
+ let elapsedTimeString = `${Math.round(elapsedTime / (365.25 * 24 * 60 * 60 * 1000))} years ago.`; // 730+ days
113
+
114
+ const elapsedTimeData = [
115
+ { min: 0, max: 44999, value: "a few seconds ago" }, // 0-44 seconds
116
+ { min: 45000, max: 89999, value: "a minute ago" }, // 45-89 seconds
117
+ { min: 90000, max: 2649999, value: `${Math.round(elapsedTime / 60000)} minutes ago`}, // 90s-44 minutes
118
+ { min: 2650000, max: 7299999, value: "an hour ago" }, // 45-120 minutes
119
+ { min: 7300000, max: 75699999, value: `${Math.round(elapsedTime / 3600000)} hours ago`}, // 2-21 hours
120
+ { min: 75700000, max: 172899999, value: "a day ago" }, // 22-48 hours
121
+ { min: 172900000, max: 2169999999, value: `${Math.round(elapsedTime / 86400000)} days ago`}, // 2-25 days
122
+ { min: 2170000000, max: 5184999999, value: "a month ago"}, // 26-60 days
123
+ { min: 5185000000, max: 27561699999, value: `${Math.round(elapsedTime / 30.44 * 24 * 60 * 60 * 1000)} months ago`}, // 60-319 days
124
+ { min: 27561700000, max: 63072999999, value: "a year ago"}, // 320-730 days
125
+ ];
126
+
127
+ for (const timeDate of elapsedTimeData) {
128
+ if (elapsedTime >= timeDate.min && elapsedTime <= timeDate.max) {
129
+ elapsedTimeString = timeDate.value;
130
+ break;
131
+ }
132
+ }
133
+
134
+ return elapsedTimeString
135
+ }
86
136
 
87
- toTimeWithMeridian() {
88
- return this.toTime() + this.toMeridian()
137
+ export const toCustomFormat = (newDate: Date | string, format = 'month_day'): string => {
138
+ const date = new Date(newDate)
139
+ if (format == "month_day") {
140
+ return `${toMonthNum(date)}/${toDay(date)}`
141
+ } else {
142
+ return `${date.toLocaleString(undefined, {month: "short"})} ${toDay(date)}`
89
143
  }
90
144
  }
145
+
146
+ export default {
147
+ toMinute,
148
+ toHour,
149
+ toDay,
150
+ toDayAbbr,
151
+ toWeekday,
152
+ toMonth,
153
+ toMonthNum,
154
+ toYear,
155
+ toTime,
156
+ toMeridiem,
157
+ toTimeZone,
158
+ toTimeWithMeridiem,
159
+ toIso,
160
+ fromNow,
161
+ toCustomFormat,
162
+ }