playbook_ui 12.13.0.pre.alpha.addingProductTokens439 → 12.14.0.pre.alpha.PLAY603datepickerquickpickinputpresetdropdown456

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_date_picker/_date_picker.scss +26 -0
  3. data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +105 -95
  4. data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +1 -1
  5. data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +60 -1
  6. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +16 -3
  7. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_on_close.jsx +43 -0
  8. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_on_close.md +3 -0
  9. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick.html.erb +8 -0
  10. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick.jsx +18 -0
  11. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_range.jsx +1 -0
  12. data/app/pb_kits/playbook/pb_date_picker/docs/example.yml +3 -0
  13. data/app/pb_kits/playbook/pb_date_picker/docs/index.js +2 -0
  14. data/app/pb_kits/playbook/pb_date_picker/plugins/quickPick.ts +166 -0
  15. data/app/pb_kits/playbook/pb_date_picker/sass_partials/_quick_pick_styles.scss +56 -0
  16. data/app/pb_kits/playbook/pb_layout/_layout.tsx +6 -1
  17. data/app/pb_kits/playbook/pb_nav/_item.tsx +5 -5
  18. data/app/pb_kits/playbook/pb_nav/_nav.tsx +2 -2
  19. data/app/pb_kits/playbook/pb_nav/_subtle_mixin.scss +1 -1
  20. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +23 -9
  21. data/app/pb_kits/playbook/tokens/_positioning.scss +13 -0
  22. data/app/pb_kits/playbook/utilities/_positioning.scss +20 -0
  23. data/app/pb_kits/playbook/utilities/globalProps.ts +11 -2
  24. data/lib/playbook/classnames.rb +1 -0
  25. data/lib/playbook/kit_base.rb +2 -0
  26. data/lib/playbook/position.rb +33 -0
  27. data/lib/playbook/version.rb +2 -2
  28. metadata +9 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5810ed238e19013cd9913f7751d768a9b0e8c29cb9fb12e7b94f040eb90252ec
4
- data.tar.gz: '08a0f2529b37414524c4dbb79c3ea1c7efa4a388ade459dc6a77836f93ab1c0e'
3
+ metadata.gz: d134719af99c9b743c91b79eaf9df31ec4f190b0ee63eef43ca0371f45285bae
4
+ data.tar.gz: 9548d090839568767077f07961bc410807d7f658c0b9c26bc732192f39f98740
5
5
  SHA512:
6
- metadata.gz: 64c3596d0dd7835e6ee4ae6b1bfd55be5a8f87f4be5f90d0a584e60c5c3d0dc89c49b82ba8936417d210daeed87487bf99a218430bf9fec5084c0074601408bb
7
- data.tar.gz: 7a51f19a279eca809c072cd7b34b39b4efc30a766d28538e1548715036076438c00d442134d26d31357239b24f9ccb4c787b2cea4015c2445d165848e1e8718b
6
+ metadata.gz: fe57e92aa08c99eba690fe145d67f01f7bdc07bea84a3697445a8231c80a3d1ce10196f4dc9239d147eefa54064334d3f065772b62414218e28d8c0b9befcc76
7
+ data.tar.gz: b61b2412844e71772d46587d98803aa254e43e100466345873958cbfe093faa37a7242be2a8b5cd0202a5e1716bd88cb63d8647f63d302d99aafe05f12bdf878
@@ -6,6 +6,7 @@
6
6
  @import "./sass_partials/month_and_year_styles";
7
7
  @import "./sass_partials/time_selection_styles";
8
8
  @import "./sass_partials/input_styles";
9
+ @import "./sass_partials/quick_pick_styles";
9
10
 
10
11
  [class^=pb_date_picker_kit] {
11
12
  .input_wrapper {
@@ -26,7 +27,32 @@
26
27
  @include transition_default;
27
28
  border-color: $primary;
28
29
  }
30
+ .add-on-card {
31
+ border-color: $primary;
32
+ }
33
+ }
34
+
35
+ @media (hover: hover) {
36
+ &:hover {
37
+ .add-on-card {
38
+ cursor: pointer;
39
+ background-color: rgba($focus_input_light,$opacity_5);
40
+ }
41
+ }
42
+ }
43
+ .text_input_wrapper_add_on .add-on-icon {
44
+ color: $text_lt_light
29
45
  }
46
+
47
+ .text_input_wrapper_add_on .add-on-right .text_input{
48
+ cursor: pointer;
49
+ }
50
+
51
+ }
52
+
53
+
54
+ .pb_popover_reference_wrapper {
55
+ display: unset !important
30
56
  }
31
57
 
32
58
  .flatpickr-calendar {
@@ -1,4 +1,4 @@
1
- import React, { useEffect } from 'react'
1
+ import React, { useEffect} from 'react'
2
2
  import classnames from 'classnames'
3
3
 
4
4
  import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
@@ -30,7 +30,7 @@ type DatePickerProps = {
30
30
  inputAria?: { [key: string]: string },
31
31
  inputData?: { [key: string]: string },
32
32
  inputOnChange?: (e: React.FormEvent<HTMLInputElement>) => void,
33
- inputValue?: any,
33
+ inputValue?: string,
34
34
  label?: string,
35
35
  maxDate: string,
36
36
  minDate: string,
@@ -39,7 +39,7 @@ type DatePickerProps = {
39
39
  placeholder?: string,
40
40
  positionElement?: HTMLElement | null,
41
41
  scrollContainer?: string,
42
- selectionType?: "month" | "week",
42
+ selectionType?: "month" | "week"| "quickpick",
43
43
  showTimezone?: boolean,
44
44
  staticPosition: boolean,
45
45
  timeFormat?: string,
@@ -78,6 +78,7 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
78
78
  mode = 'single',
79
79
  name,
80
80
  onChange = () => { void 0 },
81
+ onClose,
81
82
  pickerId,
82
83
  placeholder = 'Select Date',
83
84
  plugins = false,
@@ -95,40 +96,46 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
95
96
  const inputAriaProps = buildAriaProps(inputAria)
96
97
  const inputDataProps = buildDataProps(inputData)
97
98
 
99
+ useEffect(() => {
100
+ datePickerHelper({
101
+ allowInput,
102
+ defaultDate,
103
+ disableDate,
104
+ disableRange,
105
+ disableWeekdays,
106
+ enableTime,
107
+ format,
108
+ hideIcon,
109
+ inLine,
110
+ maxDate,
111
+ minDate,
112
+ mode,
113
+ onChange,
114
+ onClose,
115
+ pickerId,
116
+ plugins,
117
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
118
+ // @ts-ignore
119
+ position,
120
+ positionElement,
121
+ selectionType,
122
+ showTimezone,
123
+ staticPosition,
124
+ yearRange,
125
+ required: false,
126
+ }, scrollContainer)
127
+ })
128
+ const filteredProps = {...props}
129
+ delete filteredProps?.position
130
+
98
131
  const classes = classnames(
99
132
  buildCss('pb_date_picker_kit'),
100
- globalProps(props),
133
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
134
+ //@ts-ignore
135
+ globalProps(filteredProps),
101
136
  error ? 'error' : null,
102
137
  className
103
138
  )
104
-
105
- useEffect(() => {
106
- datePickerHelper({
107
- allowInput,
108
- defaultDate,
109
- disableDate,
110
- disableRange,
111
- disableWeekdays,
112
- enableTime,
113
- format,
114
- hideIcon,
115
- inLine,
116
- maxDate,
117
- minDate,
118
- mode,
119
- onChange,
120
- pickerId,
121
- plugins,
122
- position,
123
- positionElement,
124
- selectionType,
125
- showTimezone,
126
- staticPosition,
127
- yearRange,
128
- required: false,
129
- }, scrollContainer)
130
- })
131
-
132
139
  const iconWrapperClass = () => {
133
140
  let base = 'cal_icon_wrapper'
134
141
  if (dark) {
@@ -145,78 +152,81 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
145
152
 
146
153
  return (
147
154
  <div
148
- {...ariaProps}
149
- {...dataProps}
150
- className={classes}
151
- id={id}
155
+ {...ariaProps}
156
+ {...dataProps}
157
+ className={classes}
158
+ id={id}
152
159
  >
153
160
  <div
154
- {...inputAriaProps}
155
- {...inputDataProps}
156
- className="input_wrapper">
161
+ {...inputAriaProps}
162
+ {...inputDataProps}
163
+ className="input_wrapper"
164
+ >
157
165
 
158
166
  <Caption
159
- className="pb_date_picker_kit_label"
160
- text={hideLabel ? null : label}
167
+ className="pb_date_picker_kit_label"
168
+ text={hideLabel ? null : label}
161
169
  />
162
-
163
- <div className="date_picker_input_wrapper">
164
- <input
165
- autoComplete="off"
166
- className="date_picker_input"
167
- disabled={disableInput}
168
- id={pickerId}
169
- name={name}
170
- onChange={inputOnChange}
171
- placeholder={placeholder}
172
- value={inputValue}
173
- />
174
-
175
- {error && <Body
176
- status="negative"
177
- text={error}
178
- variant={null}
179
- />
180
- }
181
- </div>
182
-
183
- {!hideIcon &&
184
- <div
185
- className={iconWrapperClass()}
186
- id={`cal-icon-${pickerId}`}
187
- >
188
- <Icon
189
- className="cal_icon"
190
- icon="calendar-alt"
191
- />
192
- </div>
193
- }
194
-
195
- {hideIcon && inLine ?
196
- <div>
197
- <div
198
- className={iconWrapperClass()}
199
- id={`${pickerId}-icon-plus`}
200
- >
201
- <Icon
202
- className="date-picker-plus-icon"
203
- icon="plus"
204
- />
205
- </div>
206
- <div
207
- className={iconWrapperClass()}
208
- id={`${pickerId}-angle-down`}
209
- >
210
- <Icon
211
- className="angle_down_icon"
212
- icon="angle-down"
170
+ <>
171
+ <div className="date_picker_input_wrapper">
172
+ <input
173
+ autoComplete="off"
174
+ className="date_picker_input"
175
+ disabled={disableInput}
176
+ id={pickerId}
177
+ name={name}
178
+ onChange={inputOnChange}
179
+ placeholder={placeholder}
180
+ value={inputValue}
213
181
  />
182
+
183
+ {error &&
184
+ <Body
185
+ status="negative"
186
+ text={error}
187
+ variant={null}
188
+ />
189
+ }
214
190
  </div>
215
- </div>
216
- : null}
191
+
192
+ {!hideIcon &&
193
+ <div
194
+ className={iconWrapperClass()}
195
+ id={`cal-icon-${pickerId}`}
196
+ >
197
+ <Icon
198
+ className="cal_icon"
199
+ icon="calendar-alt"
200
+ />
201
+ </div>
202
+ }
203
+
204
+ {hideIcon && inLine ?
205
+ <div>
206
+ <div
207
+ className={iconWrapperClass()}
208
+ id={`${pickerId}-icon-plus`}
209
+ >
210
+ <Icon
211
+ className="date-picker-plus-icon"
212
+ icon="plus"
213
+ />
214
+ </div>
215
+ <div
216
+ className={iconWrapperClass()}
217
+ id={`${pickerId}-angle-down`}
218
+ >
219
+ <Icon
220
+ className="angle_down_icon"
221
+ icon="angle-down"
222
+ />
223
+ </div>
224
+ </div>
225
+ : null
226
+ }
227
+ </>
217
228
  </div>
218
229
  </div>
219
230
  )
220
231
  }
221
-
222
232
  export default DatePicker
@@ -64,4 +64,4 @@
64
64
  datePickerHelper(<%= object.date_picker_config %>, "<%= object.scroll_container %>")
65
65
  })
66
66
  <% end %>
67
- <% end %>
67
+ <% end %>
@@ -51,7 +51,7 @@ module Playbook
51
51
  prop :position_element, type: Playbook::Props::String
52
52
  prop :scroll_container, type: Playbook::Props::String
53
53
  prop :selection_type, type: Playbook::Props::Enum,
54
- values: %w[week month none],
54
+ values: %w[week month quickpick none],
55
55
  default: "none"
56
56
  prop :show_timezone, type: Playbook::Props::Boolean,
57
57
  default: false
@@ -103,6 +103,65 @@ module Playbook
103
103
  class_string += error_class
104
104
  class_string
105
105
  end
106
+
107
+ def format_date(date)
108
+ date.strftime("%m/%d/%Y")
109
+ end
110
+
111
+ def date_ranges
112
+ [
113
+ {
114
+ label: "Today",
115
+ start_date: format_date(::Date.current),
116
+ end_date: format_date(::Date.current),
117
+ },
118
+ {
119
+ label: "Yesterday",
120
+ start_date: format_date(::Date.current.yesterday),
121
+ end_date: format_date(::Date.current.yesterday),
122
+ },
123
+ {
124
+ label: "This Week",
125
+ start_date: format_date(::Date.current.beginning_of_week),
126
+ end_date: format_date(::Date.current.end_of_week),
127
+ },
128
+ {
129
+ label: "This Month",
130
+ start_date: format_date(::Date.current.beginning_of_month),
131
+ end_date: format_date(::Date.current),
132
+ },
133
+ {
134
+ label: "This Quarter",
135
+ start_date: format_date(::Date.current.beginning_of_quarter),
136
+ end_date: format_date(::Date.current),
137
+ },
138
+ {
139
+ label: "This Year",
140
+ start_date: format_date(::Date.current.beginning_of_year),
141
+ end_date: format_date(::Date.current),
142
+ },
143
+ {
144
+ label: "Last Week",
145
+ start_date: format_date(::Date.current.last_week.beginning_of_week),
146
+ end_date: format_date(::Date.current.last_week.end_of_week),
147
+ },
148
+ {
149
+ label: "Last Month",
150
+ start_date: format_date(::Date.current.last_month.beginning_of_month),
151
+ end_date: format_date(::Date.current.last_month.end_of_month),
152
+ },
153
+ {
154
+ label: "Last Quarter",
155
+ start_date: format_date(::Date.current.last_quarter.beginning_of_quarter),
156
+ end_date: format_date(::Date.current.last_quarter.end_of_quarter),
157
+ },
158
+ {
159
+ label: "Last Year",
160
+ start_date: format_date(::Date.current.last_year.beginning_of_year),
161
+ end_date: format_date(::Date.current.last_year.end_of_year),
162
+ },
163
+ ]
164
+ end
106
165
  end
107
166
  end
108
167
  end
@@ -3,6 +3,7 @@ import { BaseOptions } from 'flatpickr/dist/types/options'
3
3
  import monthSelectPlugin from 'flatpickr/dist/plugins/monthSelect'
4
4
  import weekSelect from "flatpickr/dist/plugins/weekSelect/weekSelect"
5
5
  import timeSelectPlugin from './plugins/timeSelect'
6
+ import quickPickPlugin from './plugins/quickPick'
6
7
 
7
8
  const getPositionElement = (element: string | Element) => {
8
9
  return (typeof element === 'string') ? document.querySelectorAll(element)[0] : element
@@ -19,7 +20,8 @@ type DatePickerConfig = {
19
20
  hideIcon?: boolean;
20
21
  inLine?: boolean,
21
22
  onChange: (dateStr: string, selectedDates: Date[]) => void,
22
- selectionType?: "month" | "week" | "",
23
+ selectionType?: "month" | "week" | "quickpick" | "",
24
+ onClose: (dateStr: Date[] | string, selectedDates: Date[] | string) => void,
23
25
  showTimezone?: boolean,
24
26
  staticPosition: boolean,
25
27
  timeCaption?: string,
@@ -41,6 +43,7 @@ const datePickerHelper = (config: DatePickerConfig, scrollContainer: string | HT
41
43
  minDate,
42
44
  mode,
43
45
  onChange = () => {},
46
+ onClose = () => {},
44
47
  pickerId,
45
48
  plugins,
46
49
  position = "auto",
@@ -88,18 +91,23 @@ const datePickerHelper = (config: DatePickerConfig, scrollContainer: string | HT
88
91
  }
89
92
 
90
93
  const setPlugins = () => {
91
- let pluginList = []
94
+ const pluginList = []
92
95
 
93
96
  // month and week selection
94
97
  if (selectionType === "month" || plugins.length > 0) {
95
98
  pluginList.push(monthSelectPlugin({ shorthand: true, dateFormat: 'F Y', altFormat: 'F Y' }))
96
99
  } else if ( selectionType === "week") {
97
100
  pluginList.push(weekSelect())
101
+
102
+ } else if (selectionType === "quickpick") {
103
+ //------- QUICKPICK VARIANT PLUGIN -------------//
104
+ pluginList.push(quickPickPlugin())
98
105
  }
99
106
 
100
107
  // time selection
101
108
  if (enableTime) pluginList.push(timeSelectPlugin({ caption: timeCaption, showTimezone: showTimezone}))
102
109
 
110
+
103
111
  return pluginList
104
112
  }
105
113
 
@@ -142,6 +150,9 @@ const datePickerHelper = (config: DatePickerConfig, scrollContainer: string | HT
142
150
  },
143
151
  ] : disabledParser(),
144
152
  enableTime,
153
+ locale: {
154
+ rangeSeparator: ' → '
155
+ },
145
156
  maxDate,
146
157
  minDate,
147
158
  mode,
@@ -151,9 +162,10 @@ const datePickerHelper = (config: DatePickerConfig, scrollContainer: string | HT
151
162
  window.addEventListener('resize', calendarResizer)
152
163
  if (!staticPosition && scrollContainer) attachToScroll(scrollContainer)
153
164
  }],
154
- onClose: [() => {
165
+ onClose: [(selectedDates, dateStr) => {
155
166
  window.removeEventListener('resize', calendarResizer)
156
167
  if (!staticPosition && scrollContainer) detachFromScroll(scrollContainer as HTMLElement)
168
+ onClose(selectedDates, dateStr)
157
169
  }],
158
170
  onChange: [(selectedDates, dateStr) => {
159
171
  onChange(dateStr, selectedDates)
@@ -168,6 +180,7 @@ const datePickerHelper = (config: DatePickerConfig, scrollContainer: string | HT
168
180
  static: staticPosition,
169
181
  })
170
182
 
183
+
171
184
  // ===========================================================
172
185
  // Additional JS Functionality |
173
186
  // ===========================================================
@@ -0,0 +1,43 @@
1
+ /* eslint-disable react/no-multi-comp */
2
+ import React, { useState } from 'react'
3
+ import { DatePicker,LabelValue } from '../..'
4
+
5
+
6
+ const DatePickerOnClose = (props) => {
7
+ const today = new Date()
8
+ const [dateString, setDateString] = useState(today.toLocaleDateString())
9
+ const [dateObj, setDateObj] = useState([today])
10
+
11
+ const handleOnClose = (selectedDates, dateStr) => {
12
+ setDateString(dateStr)
13
+ setDateObj(selectedDates)
14
+ }
15
+
16
+
17
+ return (
18
+ <div>
19
+ <DatePicker
20
+ defaultDate={dateString}
21
+ enableTime
22
+ marginBottom="lg"
23
+ onClose={handleOnClose}
24
+ pickerId="date-picker-on-close"
25
+ showTimezone
26
+ {...props}
27
+ />
28
+ <LabelValue
29
+ label="Date Object"
30
+ marginBottom="lg"
31
+ value={dateObj[0] ? dateObj[0].toString() : ''}
32
+ {...props}
33
+ />
34
+ <LabelValue
35
+ label="Date String"
36
+ value={dateString}
37
+ {...props}
38
+ />
39
+ </div>
40
+ )
41
+ }
42
+
43
+ export default DatePickerOnClose
@@ -0,0 +1,3 @@
1
+ The `onClose` handler function has access to two arguments: `dateStr` and `selectedDates`.
2
+
3
+ The first, `dateStr`, is a string of the chosen date. The second, `selectedDates`, is an array of selected date objects. In many use cases `selectedDates` will have only one value but you'll still need to access it from index 0.
@@ -0,0 +1,8 @@
1
+ <%= pb_rails("date_picker", props: {
2
+ allow_input: true,
3
+ mode: "range",
4
+ picker_id: "date-picker-quick-pick",
5
+ placeholder: "mm/dd/yyyy → mm/dd/yyyy",
6
+ selection_type: "quickpick"
7
+ }) %>
8
+
@@ -0,0 +1,18 @@
1
+ import React from 'react'
2
+
3
+ import DatePicker from '../_date_picker'
4
+
5
+ const DatePickerQuickPick = (props) => (
6
+ <div>
7
+ <DatePicker
8
+ allowInput
9
+ mode="range"
10
+ pickerId="date-picker-quick-pick"
11
+ placeholder="mm/dd/yyyy → mm/dd/yyyy"
12
+ selectionType="quickpick"
13
+ {...props}
14
+ />
15
+ </div>
16
+ )
17
+
18
+ export default DatePickerQuickPick
@@ -5,6 +5,7 @@ import DatePicker from '../_date_picker'
5
5
  const DatePickerRange = (props) => (
6
6
  <div>
7
7
  <DatePicker
8
+ allowInput
8
9
  defaultDate={[new Date(), new Date().fp_incr(7)]}
9
10
  mode="range"
10
11
  pickerId="date-picker-range"
@@ -21,6 +21,7 @@ examples:
21
21
  - date_picker_week: Week
22
22
  - date_picker_time: Time Selection
23
23
  - date_picker_positions: Custom Positions
24
+ - date_picker_quick_pick: Quick Pick
24
25
  - date_picker_positions_element: Custom Position (based on element)
25
26
 
26
27
  react:
@@ -31,6 +32,7 @@ examples:
31
32
  - date_picker_input: Input Field
32
33
  - date_picker_label: Label
33
34
  - date_picker_on_change: onChange
35
+ - date_picker_on_close: onClose
34
36
  - date_picker_range: Range
35
37
  - date_picker_format: Format
36
38
  - date_picker_disabled: Disabled Dates
@@ -44,4 +46,5 @@ examples:
44
46
  - date_picker_week: Week
45
47
  - date_picker_time: Time Selection
46
48
  - date_picker_positions: Custom Positions
49
+ - date_picker_quick_pick: Quick Pick
47
50
  - date_picker_positions_element: Custom Position (based on element)
@@ -19,3 +19,5 @@ export { default as DatePickerWeek } from './_date_picker_week.jsx'
19
19
  export { default as DatePickerPositions } from './_date_picker_positions.jsx'
20
20
  export { default as DatePickerPositionsElement } from './_date_picker_positions_element.jsx'
21
21
  export { default as DatePickerAllowInput } from './_date_picker_allow_input'
22
+ export { default as DatePickerQuickPick } from './_date_picker_quick_pick'
23
+ export { default as DatePickerOnClose } from './_date_picker_on_close.jsx'
@@ -0,0 +1,166 @@
1
+ import moment from 'moment'
2
+
3
+ type FpTypes = {
4
+ setDate: (arg0: any, arg1: boolean) => void,
5
+ config: { [key: string]: string },
6
+ clear: (arg0: boolean, arg1: boolean) => void,
7
+ close: () => void,
8
+ calendarContainer?: {
9
+ classList: { add: (arg0: string) => void };
10
+ prepend: (arg0: HTMLDivElement) => void;
11
+ append: (arg0: HTMLDivElement) => void;
12
+ },
13
+ loadedPlugins: string[],
14
+ };
15
+
16
+ type pluginDataType = {
17
+ ranges: { [key: string]: Date[] },
18
+ rangesNav: HTMLUListElement,
19
+ rangesButtons: [] | any,
20
+ }
21
+
22
+ const quickPickPlugin = () => {
23
+ return function (fp: FpTypes & any): any {
24
+
25
+ // variable that holds the ranges available
26
+ const ranges = {
27
+ 'Today': [new Date(), new Date()],
28
+ 'Yesterday': [moment().subtract(1, 'days').toDate(), moment().subtract(1, 'days').toDate()],
29
+ 'This week': [moment().startOf('week').toDate(), moment().endOf('week').toDate()],
30
+ 'This month': [moment().startOf('month').toDate(), moment().endOf('month').toDate()],
31
+ 'This quarter': [moment().startOf('quarter').toDate(), moment().endOf('quarter').toDate()],
32
+ 'This year': [moment().startOf('year').toDate(), moment().endOf('year').toDate()],
33
+ 'Last week': [
34
+ moment().subtract(1, 'week').startOf('week').toDate(),
35
+ moment().subtract(1, 'week').endOf('week').toDate()
36
+ ],
37
+ 'Last month': [
38
+ moment().subtract(1, 'month').startOf('month').toDate(),
39
+ moment().subtract(1, 'month').endOf('month').toDate()
40
+ ],
41
+ 'Last quarter': [
42
+ moment().subtract(1, 'quarter').startOf('quarter').toDate(),
43
+ moment().subtract(1, 'quarter').endOf('quarter').toDate()
44
+ ],
45
+ 'Last year': [
46
+ moment().subtract(1, 'year').startOf('year').toDate(),
47
+ moment().subtract(1, 'year').endOf('year').toDate()
48
+ ]
49
+ }
50
+ //creating the ul element for the nav dropdown and giving it classnames
51
+ const rangesNav = document.createElement('ul');
52
+
53
+ // creating the pluginData object that will hold the properties of this plugin
54
+ const pluginData: pluginDataType = {
55
+ ranges: ranges,
56
+ rangesNav: rangesNav,
57
+ rangesButtons: [],
58
+ };
59
+
60
+ /**
61
+ * @param {string} label
62
+ * @returns HTML Element
63
+ */
64
+
65
+ //funciton for creating the range buttons in the nav
66
+ const addRangeButton = (label: string) => {
67
+
68
+ // create the button element and add class and text
69
+ const button = document.createElement('a');
70
+ button.className = "nav-item-link";
71
+ const itemLabel = document.createElement('span')
72
+ itemLabel.className = "nav-item-text"
73
+ itemLabel.innerHTML = label;
74
+
75
+ // create li elements inside the dropdown
76
+ const item = document.createElement('li');
77
+ item.className = "nav-item";
78
+
79
+ pluginData.rangesButtons[label] = button;
80
+
81
+ // append span text to anchor tag
82
+ pluginData.rangesButtons[label].appendChild(itemLabel)
83
+
84
+ // append those anchor tags to the li items
85
+ item.appendChild(pluginData.rangesButtons[label]);
86
+
87
+ // append the li item to the ul rangeNav prop
88
+ pluginData.rangesNav.appendChild(item);
89
+
90
+ // return the ranges buton prop
91
+ return pluginData.rangesButtons[label];
92
+ };
93
+
94
+ const selectActiveRangeButton = (selectedDates: Array<string>) => {
95
+ const current = pluginData.rangesNav.querySelector('.active');
96
+
97
+ if (current) {
98
+ current.classList.remove('active');
99
+ }
100
+ /** conditional statment to extract start and end dates from selectedDates,
101
+ * then loop through ranges prop in pluginData
102
+ * and check if chosen dates equal to a date in the ranges prop
103
+ * if they are equal, add the active class
104
+ */
105
+ if (selectedDates.length > 0) {
106
+
107
+ const startDate = moment(selectedDates[0]);
108
+ const endDate = selectedDates.length > 1 ? moment(selectedDates[1]) : startDate;
109
+
110
+ for (const [label, range] of Object.entries(pluginData.ranges)) {
111
+ if (startDate.isSame(moment(range[0]), 'day') && endDate.isSame(moment(range[1]), 'day')) {
112
+ pluginData.rangesButtons[label].classList.add('active');
113
+ break;
114
+ }
115
+ }
116
+ }
117
+
118
+ }
119
+
120
+
121
+ return {
122
+ // onReady is a hook from flatpickr that runs when calender is in a ready state
123
+ onReady(selectedDates: Array<string>) {
124
+ // loop through the ranges and create an anchor tag for each range and add an event listiner to set the date when user clicks on a date range
125
+ for (const [label, range] of Object.entries(pluginData.ranges)) {
126
+ addRangeButton(label).addEventListener('click', function () {
127
+
128
+ const start = moment(range[0]).toDate();
129
+ const end = moment(range[1]).toDate();
130
+
131
+ if (!start) {
132
+ fp.clear();
133
+ }
134
+ else {
135
+ fp.setDate([start, end], true);
136
+ }
137
+
138
+ fp.close();
139
+ });
140
+ }
141
+
142
+ // conditional to check if there is a dropdown to add it to the calendar container and git it the classes it needs
143
+ if (pluginData.rangesNav.children.length > 0) {
144
+
145
+ fp.calendarContainer.prepend(pluginData.rangesNav);
146
+ pluginData.rangesNav.classList.add('quick-pick-ul')
147
+ fp.calendarContainer.classList.add('quick-pick-drop-down');
148
+
149
+ /**
150
+ *
151
+ * @param {Array} selectedDates
152
+ */
153
+
154
+ // function to give the active butto the active class
155
+ selectActiveRangeButton(selectedDates);
156
+ }
157
+
158
+ },
159
+ onValueUpdate(selectedDates: Array<string>) {
160
+ selectActiveRangeButton(selectedDates);
161
+ }
162
+ };
163
+ };
164
+ }
165
+
166
+ export default quickPickPlugin;
@@ -0,0 +1,56 @@
1
+ @import "../../tokens/animation-curves";
2
+ @import "../../tokens/colors";
3
+ @import "../../tokens/typography";
4
+ @import "../../tokens/titles";
5
+
6
+ // used to display dropdown on the left of the calender
7
+ .quick-pick-drop-down {
8
+ width: auto;
9
+ display: grid;
10
+ }
11
+
12
+ .quick-pick-ul {
13
+ padding: 0;
14
+ margin: 0;
15
+ list-style: none;
16
+ }
17
+
18
+ .nav-item {
19
+ list-style: none;
20
+ border-radius: 6px;
21
+ border-bottom: 0;
22
+ margin: 8px 14px;
23
+ }
24
+
25
+ .nav-item-link {
26
+ text-decoration: none;
27
+ display: flex;
28
+ align-items: center;
29
+ border: none;
30
+ padding: 8px 14px;
31
+ transition-property: color, background-color;
32
+ transition-duration: 0.15s;
33
+ transition-timing-function: $bezier;
34
+ border-radius: 6px;
35
+ line-height: 1.4;
36
+ color: $charcoal;
37
+ font-size: $font_default;
38
+ font-weight: $regular;
39
+ &.active {
40
+ background-color: rgba($primary, 0.03);
41
+ color: $primary;
42
+ letter-spacing: normal;
43
+ }
44
+ @media (hover:hover) {
45
+ &:hover {
46
+ cursor: pointer;
47
+ background-color: rgba($primary, 0.03);
48
+ color: $primary;
49
+ }
50
+ }
51
+ }
52
+
53
+ // Hide the calendar
54
+ .quick-pick-drop-down > .flatpickr-months, .quick-pick-drop-down > .flatpickr-innerContainer {
55
+ display: none;
56
+ }
@@ -151,6 +151,10 @@ const Layout = (props: LayoutPropTypes) => {
151
151
  const nonSideChildren = layoutChildren.filter(
152
152
  (child: React.ReactElement & {type: {displayName: string}}) => child.type?.displayName !== 'Side'
153
153
  )
154
+
155
+ const filteredProps = {...props}
156
+ delete filteredProps?.position
157
+
154
158
  return (
155
159
  <div
156
160
  {...ariaProps}
@@ -159,7 +163,8 @@ const Layout = (props: LayoutPropTypes) => {
159
163
  layoutCss,
160
164
  layoutCollapseCss,
161
165
  className,
162
- globalProps(props)
166
+ //@ts-ignore
167
+ globalProps(filteredProps)
163
168
  )}
164
169
  >
165
170
  {subComponentTags('Side')}
@@ -13,14 +13,14 @@ type NavItemProps = {
13
13
  children?: React.ReactNode[] | React.ReactNode,
14
14
  className?: string,
15
15
  data?: object,
16
- iconLeft: string,
17
- iconRight: string,
16
+ iconLeft?: string,
17
+ iconRight?: string,
18
18
  id?: string,
19
- imageUrl: string,
20
- link: string,
19
+ imageUrl?: string,
20
+ link?: string,
21
21
  onClick?: React.MouseEventHandler<HTMLElement>,
22
22
  target?: '_blank' | '_self' | '_parent' | '_top',
23
- text: string,
23
+ text?: string,
24
24
  }
25
25
 
26
26
  const NavItem = (props: NavItemProps) => {
@@ -17,8 +17,8 @@ type NavProps = {
17
17
  id?: string,
18
18
  onClick?: React.MouseEventHandler<HTMLElement>,
19
19
  orientation?: "vertical" | "horizontal",
20
- link: string,
21
- title: string,
20
+ link?: string,
21
+ title?: string,
22
22
  variant?: "normal" | "subtle",
23
23
  }
24
24
 
@@ -44,7 +44,7 @@
44
44
  &[class*=_active] [class*=_link] {
45
45
  @include pb_title_4;
46
46
  color: $primary;
47
- letter-spacing: normal;
47
+ letter-spacing: normal;
48
48
  }
49
49
  }
50
50
  }
@@ -89,6 +89,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
89
89
  const [itiInit, setItiInit] = useState<any>()
90
90
  const [error, setError] = useState('')
91
91
  const [dropDownIsOpen, setDropDownIsOpen] = useState(false)
92
+ const [selectedData, setSelectedData] = useState()
92
93
 
93
94
  const validateTooLongNumber = (itiInit: any) => {
94
95
  const error = itiInit.getValidationError()
@@ -121,10 +122,16 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
121
122
  validateOnlyNumbers()
122
123
  }
123
124
 
125
+ const getCurrentSelectedData = (itiInit: any, inputValue: string) => {
126
+ return { ...itiInit.getSelectedCountryData(), number: inputValue }
127
+ }
128
+
124
129
  const handleOnChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
125
130
  setInputValue(evt.target.value)
126
131
  validateTooLongNumber(itiInit)
127
- onChange(evt)
132
+ const phoneNumberData = getCurrentSelectedData(itiInit, evt.target.value)
133
+ setSelectedData(phoneNumberData)
134
+ onChange(phoneNumberData)
128
135
  isValid(itiInit.isValidNumber())
129
136
  }
130
137
 
@@ -136,15 +143,21 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
136
143
 
137
144
  useEffect(() => {
138
145
  const telInputInit = new intlTelInput(inputRef.current, {
139
- separateDialCode: true,
140
- preferredCountries,
141
- allowDropdown: !disabled,
142
- initialCountry,
143
- onlyCountries,
144
- }
146
+ separateDialCode: true,
147
+ preferredCountries,
148
+ allowDropdown: !disabled,
149
+ initialCountry,
150
+ onlyCountries,
151
+ }
145
152
  )
146
-
147
- inputRef.current.addEventListener("countrychange", () => validateTooLongNumber(telInputInit))
153
+
154
+ inputRef.current.addEventListener("countrychange", (evt: Event) => {
155
+ validateTooLongNumber(telInputInit)
156
+ const phoneNumberData = getCurrentSelectedData(telInputInit, (evt.target as HTMLInputElement).value)
157
+ setSelectedData(phoneNumberData)
158
+ onChange(phoneNumberData)
159
+ })
160
+
148
161
  inputRef.current.addEventListener("open:countrydropdown", () => setDropDownIsOpen(true))
149
162
  inputRef.current.addEventListener("close:countrydropdown", () => setDropDownIsOpen(false))
150
163
 
@@ -156,6 +169,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
156
169
  <TextInput
157
170
  className={dropDownIsOpen ? 'dropdown_open' : ''}
158
171
  dark={dark}
172
+ data-phone-number={JSON.stringify(selectedData)}
159
173
  disabled={disabled}
160
174
  error={error}
161
175
  id={id}
@@ -1,3 +1,16 @@
1
+ $relative: relative !default;
2
+ $absolute: absolute !default;
3
+ $fixed: fixed !default;
4
+ $sticky: sticky !default;
5
+ $static: static !default;
6
+ $position: (
7
+ relative: $relative,
8
+ absolute: $absolute,
9
+ fixed: $fixed,
10
+ sticky: $sticky,
11
+ static: $static
12
+ );
13
+
1
14
  // z_index variables
2
15
  $z_1: 100 !default;
3
16
  $z_2: 200 !default;
@@ -1,3 +1,23 @@
1
+ .position_relative {
2
+ position: relative;
3
+ }
4
+
5
+ .position_absolute {
6
+ position: absolute;
7
+ }
8
+
9
+ .position_fixed {
10
+ position: fixed;
11
+ }
12
+
13
+ .position_sticky {
14
+ position: sticky;
15
+ }
16
+
17
+ .position_static {
18
+ position: static;
19
+ }
20
+
1
21
  .z_index_1 {
2
22
  z-index: 100;
3
23
  }
@@ -100,6 +100,10 @@ type Padding = {
100
100
  padding?: AllSizes,
101
101
  }
102
102
 
103
+ type Position = {
104
+ position?: "relative" | "absolute" | "fixed" | "sticky" | "static",
105
+ }
106
+
103
107
  type Shadow = {
104
108
  shadow?: "none" | "deep" | "deeper" | "deepest",
105
109
  }
@@ -115,7 +119,7 @@ export type GlobalProps = AlignContent & AlignItems & AlignSelf &
115
119
  BorderRadius & Cursor & Dark & Display & DisplaySizes & Flex & FlexDirection &
116
120
  FlexGrow & FlexShrink & FlexWrap & JustifyContent & JustifySelf &
117
121
  LineHeight & Margin & MaxWidth & NumberSpacing & Order & Padding &
118
- Shadow & ZIndex
122
+ Position & Shadow & ZIndex
119
123
 
120
124
  const getResponsivePropClasses = (prop: {[key: string]: string}, classPrefix: string) => {
121
125
  const keys: string[] = Object.keys(prop)
@@ -283,7 +287,12 @@ const PROP_CATEGORIES: {[key:string]: (props: {[key: string]: any}) => string} =
283
287
  } else {
284
288
  return order ? `flex_order_${order}` : ''
285
289
  }
286
- }
290
+ },
291
+ positionProps: ({ position }: Position) => {
292
+ let css = ''
293
+ css += position && position !== 'static' ? `position_${position}` : ''
294
+ return css
295
+ },
287
296
  }
288
297
 
289
298
  type DefaultProps = {[key: string]: string} | Record<string, unknown>
@@ -31,6 +31,7 @@ module Playbook
31
31
  flex_grow_props,
32
32
  flex_shrink_props,
33
33
  order_props,
34
+ position_props,
34
35
  ].compact.join(" ")
35
36
  end
36
37
 
@@ -19,6 +19,7 @@ require "playbook/flex"
19
19
  require "playbook/flex_grow"
20
20
  require "playbook/flex_shrink"
21
21
  require "playbook/order"
22
+ require "playbook/position"
22
23
 
23
24
  module Playbook
24
25
  class KitBase < ViewComponent::Base
@@ -43,6 +44,7 @@ module Playbook
43
44
  include Playbook::FlexGrow
44
45
  include Playbook::FlexShrink
45
46
  include Playbook::Order
47
+ include Playbook::Position
46
48
 
47
49
  prop :id
48
50
  prop :data, type: Playbook::Props::Hash, default: {}
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module Position
5
+ def self.included(base)
6
+ base.prop :position
7
+ end
8
+
9
+ private
10
+
11
+ def position_props
12
+ selected_props = position_options.keys.select { |sk| try(sk) }
13
+ return nil unless selected_props.present?
14
+
15
+ selected_props.map do |k|
16
+ value = send(k)
17
+ return nil unless position_values.include? value
18
+
19
+ "position_#{value}"
20
+ end.compact.join(" ")
21
+ end
22
+
23
+ def position_options
24
+ {
25
+ position: "position",
26
+ }
27
+ end
28
+
29
+ def position_values
30
+ %w[relative absolute fixed sticky]
31
+ end
32
+ end
33
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playbook
4
- PREVIOUS_VERSION = "12.13.0"
5
- VERSION = "12.13.0.pre.alpha.addingProductTokens439"
4
+ PREVIOUS_VERSION = "12.14.0"
5
+ VERSION = "12.14.0.pre.alpha.PLAY603datepickerquickpickinputpresetdropdown456"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: playbook_ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.13.0.pre.alpha.addingProductTokens439
4
+ version: 12.14.0.pre.alpha.PLAY603datepickerquickpickinputpresetdropdown456
5
5
  platform: ruby
6
6
  authors:
7
7
  - Power UX
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-04-06 00:00:00.000000000 Z
12
+ date: 2023-04-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -738,11 +738,15 @@ files:
738
738
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_month_and_year.md
739
739
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_on_change.jsx
740
740
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_on_change.md
741
+ - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_on_close.jsx
742
+ - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_on_close.md
741
743
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions.html.erb
742
744
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions.jsx
743
745
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions.md
744
746
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions_element.html.erb
745
747
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions_element.jsx
748
+ - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick.html.erb
749
+ - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick.jsx
746
750
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_range.html.erb
747
751
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_range.jsx
748
752
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_time.html.erb
@@ -757,6 +761,7 @@ files:
757
761
  - app/pb_kits/playbook/pb_date_picker/docs/_description.md
758
762
  - app/pb_kits/playbook/pb_date_picker/docs/example.yml
759
763
  - app/pb_kits/playbook/pb_date_picker/docs/index.js
764
+ - app/pb_kits/playbook/pb_date_picker/plugins/quickPick.ts
760
765
  - app/pb_kits/playbook/pb_date_picker/plugins/timeSelect.ts
761
766
  - app/pb_kits/playbook/pb_date_picker/sass_partials/_calendar_input_icon.scss
762
767
  - app/pb_kits/playbook/pb_date_picker/sass_partials/_day_styles.scss
@@ -766,6 +771,7 @@ files:
766
771
  - app/pb_kits/playbook/pb_date_picker/sass_partials/_input_styles.scss
767
772
  - app/pb_kits/playbook/pb_date_picker/sass_partials/_month_and_year_styles.scss
768
773
  - app/pb_kits/playbook/pb_date_picker/sass_partials/_overrides.scss
774
+ - app/pb_kits/playbook/pb_date_picker/sass_partials/_quick_pick_styles.scss
769
775
  - app/pb_kits/playbook/pb_date_picker/sass_partials/_time_selection_styles.scss
770
776
  - app/pb_kits/playbook/pb_date_picker/sass_partials/_week_styles.scss
771
777
  - app/pb_kits/playbook/pb_date_range_inline/_date_range_inline.scss
@@ -2438,6 +2444,7 @@ files:
2438
2444
  - lib/playbook/pb_doc_helper.rb
2439
2445
  - lib/playbook/pb_forms_helper.rb
2440
2446
  - lib/playbook/pb_kit_helper.rb
2447
+ - lib/playbook/position.rb
2441
2448
  - lib/playbook/props.rb
2442
2449
  - lib/playbook/props/array.rb
2443
2450
  - lib/playbook/props/base.rb