playbook_ui 18.2.0.pre.rc.2 → 18.2.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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_background/_background.tsx +3 -1
- data/app/pb_kits/playbook/pb_background/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_caption/_caption.tsx +3 -1
- data/app/pb_kits/playbook/pb_caption/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_container/_container.tsx +3 -1
- data/app/pb_kits/playbook/pb_container/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_currency/_currency.tsx +3 -1
- data/app/pb_kits/playbook/pb_currency/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_dashboard_value/_dashboard_value.tsx +3 -1
- data/app/pb_kits/playbook/pb_dashboard_value/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_detail/_detail.tsx +3 -1
- data/app/pb_kits/playbook/pb_detail/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +6 -5
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_custom.md +7 -2
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_custom_rails.md +7 -2
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_enable_time.html.erb +33 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_enable_time.jsx +42 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_enable_time.md +24 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_highlight.jsx +101 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_highlight.md +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/index.js +2 -0
- data/app/pb_kits/playbook/pb_dropdown/index.js +19 -10
- data/app/pb_kits/playbook/pb_dropdown/quickpick/index.ts +60 -18
- data/app/pb_kits/playbook/pb_dropdown/quickpick_helper.rb +92 -3
- data/app/pb_kits/playbook/pb_dropdown/utilities/index.ts +8 -1
- data/app/pb_kits/playbook/pb_dropdown/utilities/quickpickDateSync.ts +137 -0
- data/app/pb_kits/playbook/pb_filter/Filter/InteractiveFilter.tsx +1 -1
- data/app/pb_kits/playbook/pb_highlight/_highlight.tsx +3 -1
- data/app/pb_kits/playbook/pb_highlight/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_icon_stat_value/_icon_stat_value.tsx +3 -1
- data/app/pb_kits/playbook/pb_icon_stat_value/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_icon_value/_icon_value.tsx +3 -1
- data/app/pb_kits/playbook/pb_icon_value/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_label_value/_label_value.tsx +3 -1
- data/app/pb_kits/playbook/pb_label_value/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_map/docs/_map_default.md +3 -3
- data/app/pb_kits/playbook/pb_message/_message.tsx +3 -1
- data/app/pb_kits/playbook/pb_message/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_multiple_users/_multiple_users.tsx +3 -1
- data/app/pb_kits/playbook/pb_multiple_users/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_multiple_users_stacked/_multiple_users_stacked.tsx +4 -2
- data/app/pb_kits/playbook/pb_multiple_users_stacked/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/MoreExtensionsDropdown.tsx +10 -3
- data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/Toolbar.tsx +16 -1
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_playground.json +2 -3
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_playground.overrides.json +2 -3
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_attributes.jsx +1 -5
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_default.jsx +1 -5
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_default.md +2 -3
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_focus.jsx +1 -5
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_height.jsx +3 -13
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_inline.jsx +1 -5
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_label.jsx +2 -3
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_markdown_support.jsx +1 -2
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_min_height.jsx +3 -13
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_preview.jsx +1 -5
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_required_indicator.jsx +1 -5
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_simple.jsx +1 -5
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_sticky.jsx +1 -5
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_templates.jsx +1 -5
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_more_extensions.jsx +3 -8
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_more_extensions.md +1 -1
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_default.md +2 -2
- data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.test.js +2 -1
- data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor_advanced.test.js +7 -5
- data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor_rails.js +15 -4
- data/app/pb_kits/playbook/pb_stat_value/_stat_value.tsx +3 -1
- data/app/pb_kits/playbook/pb_stat_value/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_table/_table.tsx +70 -197
- data/app/pb_kits/playbook/pb_table/index.ts +53 -122
- data/app/pb_kits/playbook/pb_table/styles/_sticky_columns.scss +26 -3
- data/app/pb_kits/playbook/pb_table/utilities/stickyColumns.test.ts +266 -0
- data/app/pb_kits/playbook/pb_table/utilities/stickyColumns.ts +145 -0
- data/app/pb_kits/playbook/pb_title_count/_title_count.tsx +3 -1
- data/app/pb_kits/playbook/pb_title_count/kit.schema.json +1 -0
- data/app/pb_kits/playbook/pb_title_detail/_title_detail.tsx +3 -1
- data/app/pb_kits/playbook/pb_title_detail/kit.schema.json +1 -0
- data/app/pb_kits/playbook/utilities/test/globalProps/onClick.test.js +237 -0
- data/dist/ai/all-schemas.json +16 -0
- data/dist/ai/forms.json +1 -1
- data/dist/ai/index.json +2 -2
- data/dist/ai/kits/background.schema.json +1 -0
- data/dist/ai/kits/caption.schema.json +1 -0
- data/dist/ai/kits/container.schema.json +1 -0
- data/dist/ai/kits/currency.schema.json +1 -0
- data/dist/ai/kits/dashboard_value.schema.json +1 -0
- data/dist/ai/kits/detail.schema.json +1 -0
- data/dist/ai/kits/highlight.schema.json +1 -0
- data/dist/ai/kits/icon_stat_value.schema.json +1 -0
- data/dist/ai/kits/icon_value.schema.json +1 -0
- data/dist/ai/kits/label_value.schema.json +1 -0
- data/dist/ai/kits/message.schema.json +1 -0
- data/dist/ai/kits/multiple_users.schema.json +1 -0
- data/dist/ai/kits/multiple_users_stacked.schema.json +1 -0
- data/dist/ai/kits/stat_value.schema.json +1 -0
- data/dist/ai/kits/title_count.schema.json +1 -0
- data/dist/ai/kits/title_detail.schema.json +1 -0
- data/dist/ai/playgrounds/rich_text_editor.json +1 -1
- data/dist/chunks/{_detail-BqqzPTNr.js → _detail-Bsvl694i.js} +2 -2
- data/dist/chunks/{_pb_line_graph-BGyCJjgG.js → _pb_line_graph-Du7xE9vl.js} +1 -1
- data/dist/chunks/_table-Bf6LGyL9.js +1 -0
- data/dist/chunks/_typeahead-w6S5Vx4b.js +1 -0
- data/dist/chunks/{globalProps-K1DCn3il.js → globalProps-B120NbSJ.js} +1 -1
- data/dist/chunks/{lib-7vm9BMqp.js → lib-Buo6zHEw.js} +1 -1
- data/dist/chunks/quickpickDateSync-DLDx4zce.js +1 -0
- data/dist/chunks/{time_picker_helper-BZutIzB3.js → time_picker_helper-CYGg0UQ0.js} +1 -1
- data/dist/chunks/vendor.js +2 -2
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +19 -13
- data/dist/chunks/_table-CEZU0qUK.js +0 -1
- data/dist/chunks/_typeahead-C7iPR5ZF.js +0 -1
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
// This provides date range options similar to the DatePicker QuickPick functionality
|
|
3
3
|
|
|
4
4
|
import DateTime from '../../pb_kit/dateTime';
|
|
5
|
+
import {
|
|
6
|
+
endOfDay,
|
|
7
|
+
parseQuickPickDateOnly,
|
|
8
|
+
parseQuickPickDateTime,
|
|
9
|
+
startOfDay,
|
|
10
|
+
stringHasExplicitTime,
|
|
11
|
+
} from '../utilities/quickpickDateSync';
|
|
5
12
|
|
|
6
13
|
type QuickPickOption = {
|
|
7
14
|
label: string;
|
|
@@ -13,7 +20,7 @@ type QuickPickOption = {
|
|
|
13
20
|
|
|
14
21
|
type CustomQuickPickDate = {
|
|
15
22
|
label: string;
|
|
16
|
-
value: string
|
|
23
|
+
value: Array<Date | string> | { timePeriod: string; amount: number };
|
|
17
24
|
};
|
|
18
25
|
|
|
19
26
|
type CustomQuickPickDates = {
|
|
@@ -21,6 +28,11 @@ type CustomQuickPickDates = {
|
|
|
21
28
|
dates: CustomQuickPickDate[];
|
|
22
29
|
};
|
|
23
30
|
|
|
31
|
+
const toQuickPickRange = (start: Date, end: Date): Date[] => [
|
|
32
|
+
startOfDay(start),
|
|
33
|
+
endOfDay(end),
|
|
34
|
+
];
|
|
35
|
+
|
|
24
36
|
// Helper function to calculate date range from timePeriod and amount
|
|
25
37
|
const calculateDateRange = (timePeriod: string, amount: number): Date[] => {
|
|
26
38
|
const endDate = new Date();
|
|
@@ -45,7 +57,7 @@ const calculateDateRange = (timePeriod: string, amount: number): Date[] => {
|
|
|
45
57
|
default:
|
|
46
58
|
throw new Error('Invalid time period');
|
|
47
59
|
}
|
|
48
|
-
return
|
|
60
|
+
return toQuickPickRange(startDate, endDate);
|
|
49
61
|
};
|
|
50
62
|
|
|
51
63
|
// Helper to format date for display
|
|
@@ -57,13 +69,32 @@ const formatDate = (date: Date) => {
|
|
|
57
69
|
return `${month}/${day}/${year}`;
|
|
58
70
|
};
|
|
59
71
|
|
|
72
|
+
// Date objects keep their authored time (including midnight / 23:59:00).
|
|
73
|
+
// Date-only strings get SOD/EOD; timed strings keep their parsed time.
|
|
74
|
+
const parseCustomDateBoundary = (value: Date | string): Date => {
|
|
75
|
+
if (value instanceof Date) return value;
|
|
76
|
+
if (stringHasExplicitTime(value)) {
|
|
77
|
+
return parseQuickPickDateTime(value) ?? new Date(value);
|
|
78
|
+
}
|
|
79
|
+
return parseQuickPickDateOnly(value) ?? new Date(value);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const boundaryHasExplicitTime = (value: Date | string): boolean =>
|
|
83
|
+
value instanceof Date || stringHasExplicitTime(value);
|
|
84
|
+
|
|
60
85
|
// Helper to create a QuickPickOption from a custom date
|
|
61
86
|
const createOptionFromCustomDate = (customDate: CustomQuickPickDate): QuickPickOption => {
|
|
62
87
|
let dateRange: Date[];
|
|
63
|
-
|
|
88
|
+
|
|
64
89
|
if (Array.isArray(customDate.value)) {
|
|
65
|
-
|
|
66
|
-
|
|
90
|
+
const startRaw = parseCustomDateBoundary(customDate.value[0]);
|
|
91
|
+
const endRaw = parseCustomDateBoundary(customDate.value[1]);
|
|
92
|
+
const startHasTime = boundaryHasExplicitTime(customDate.value[0]);
|
|
93
|
+
const endHasTime = boundaryHasExplicitTime(customDate.value[1]);
|
|
94
|
+
dateRange = [
|
|
95
|
+
startHasTime ? startRaw : startOfDay(startRaw),
|
|
96
|
+
endHasTime ? endRaw : endOfDay(endRaw),
|
|
97
|
+
];
|
|
67
98
|
} else {
|
|
68
99
|
// Calculate from timePeriod and amount
|
|
69
100
|
dateRange = calculateDateRange(
|
|
@@ -81,6 +112,17 @@ const createOptionFromCustomDate = (customDate: CustomQuickPickDate): QuickPickO
|
|
|
81
112
|
};
|
|
82
113
|
};
|
|
83
114
|
|
|
115
|
+
const option = (label: string, start: Date, end: Date, id: string): QuickPickOption => {
|
|
116
|
+
const value = toQuickPickRange(start, end);
|
|
117
|
+
return {
|
|
118
|
+
label,
|
|
119
|
+
value,
|
|
120
|
+
formattedStartDate: formatDate(value[0]),
|
|
121
|
+
formattedEndDate: formatDate(value[1]),
|
|
122
|
+
id,
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
|
|
84
126
|
// Helper to get QuickPick options with date ranges
|
|
85
127
|
const getQuickPickOptions = (rangeEndsToday = false, customQuickPickDates?: CustomQuickPickDates): QuickPickOption[] => {
|
|
86
128
|
const today = new Date();
|
|
@@ -107,30 +149,30 @@ const getQuickPickOptions = (rangeEndsToday = false, customQuickPickDates?: Cust
|
|
|
107
149
|
const lastYearEndDate = DateTime.getPreviousYearEndDate(new Date());
|
|
108
150
|
|
|
109
151
|
const defaultOptions: QuickPickOption[] = [
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
152
|
+
option('Today', today, today, 'quickpick-today'),
|
|
153
|
+
option('Yesterday', yesterday, yesterday, 'quickpick-yesterday'),
|
|
154
|
+
option('This Week', thisWeekStartDate, thisWeekEndDate, 'quickpick-this-week'),
|
|
155
|
+
option('This Month', thisMonthStartDate, thisMonthEndDate, 'quickpick-this-month'),
|
|
156
|
+
option('This Quarter', thisQuarterStartDate, thisQuarterEndDate, 'quickpick-this-quarter'),
|
|
157
|
+
option('This Year', thisYearStartDate, thisYearEndDate, 'quickpick-this-year'),
|
|
158
|
+
option('Last Week', lastWeekStartDate, lastWeekEndDate, 'quickpick-last-week'),
|
|
159
|
+
option('Last Month', lastMonthStartDate, lastMonthEndDate, 'quickpick-last-month'),
|
|
160
|
+
option('Last Quarter', lastQuarterStartDate, lastQuarterEndDate, 'quickpick-last-quarter'),
|
|
161
|
+
option('Last Year', lastYearStartDate, lastYearEndDate, 'quickpick-last-year'),
|
|
120
162
|
];
|
|
121
163
|
|
|
122
164
|
// Handle customQuickPickDates and override logic
|
|
123
165
|
if (customQuickPickDates && customQuickPickDates.dates && customQuickPickDates.dates.length > 0) {
|
|
124
166
|
const customOptions = customQuickPickDates.dates.map(createOptionFromCustomDate);
|
|
125
|
-
|
|
167
|
+
|
|
126
168
|
if (customQuickPickDates.override === false) {
|
|
127
169
|
return [...defaultOptions, ...customOptions];
|
|
128
170
|
}
|
|
129
|
-
|
|
171
|
+
|
|
130
172
|
return customOptions;
|
|
131
173
|
}
|
|
132
174
|
|
|
133
175
|
return defaultOptions;
|
|
134
176
|
};
|
|
135
177
|
|
|
136
|
-
export default getQuickPickOptions
|
|
178
|
+
export default getQuickPickOptions
|
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
module Playbook
|
|
4
4
|
module PbDropdown
|
|
5
5
|
module QuickpickHelper
|
|
6
|
+
# Marker for absolute ISO boundaries (Z / numeric offset). Wall-clock
|
|
7
|
+
# DateTime.civil also has offset 0, so offset alone cannot distinguish —
|
|
8
|
+
# format_date / format_value use this flag to preserve Z/±HH:MM on emit.
|
|
9
|
+
module AbsoluteInstant
|
|
10
|
+
def absolute_instant?
|
|
11
|
+
true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
private_constant :AbsoluteInstant
|
|
15
|
+
|
|
6
16
|
class << self
|
|
7
17
|
def get_quickpick_options(range_ends_today: false, custom_quick_pick_dates: {})
|
|
8
18
|
default_options = build_default_options(range_ends_today)
|
|
@@ -77,7 +87,7 @@ module Playbook
|
|
|
77
87
|
{
|
|
78
88
|
id: "quickpick-#{label.downcase.gsub(/\s+/, '-')}",
|
|
79
89
|
label: label,
|
|
80
|
-
value: [start_date
|
|
90
|
+
value: [format_value(start_date), format_value(end_date)],
|
|
81
91
|
formatted_start_date: format_date(start_date),
|
|
82
92
|
formatted_end_date: format_date(end_date),
|
|
83
93
|
}
|
|
@@ -86,7 +96,7 @@ module Playbook
|
|
|
86
96
|
def calculate_date_range(value)
|
|
87
97
|
# Parse date strings if value is an array
|
|
88
98
|
if value.is_a?(Array)
|
|
89
|
-
[
|
|
99
|
+
[parse_boundary(value[0]), parse_boundary(value[1])]
|
|
90
100
|
else
|
|
91
101
|
# Calculate date range from time_period and amount
|
|
92
102
|
time_period = value[:time_period] || value["time_period"] || value[:timePeriod] || value["timePeriod"]
|
|
@@ -99,6 +109,19 @@ module Playbook
|
|
|
99
109
|
end
|
|
100
110
|
end
|
|
101
111
|
|
|
112
|
+
def parse_boundary(date_str)
|
|
113
|
+
date_str = date_str.to_s
|
|
114
|
+
if string_has_explicit_time?(date_str)
|
|
115
|
+
parse_datetime_string(date_str)
|
|
116
|
+
else
|
|
117
|
+
parse_date_string(date_str)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def string_has_explicit_time?(value)
|
|
122
|
+
value.match?(/[T\s]\d{1,2}:\d{2}/) || value.match?(/\d{1,2}:\d{2}\s*(AM|PM)/i)
|
|
123
|
+
end
|
|
124
|
+
|
|
102
125
|
def parse_date_string(date_str)
|
|
103
126
|
# Handle US date format (MM/DD/YYYY) because Ruby's Date.parse defaults to European format (DD/MM/YYYY)
|
|
104
127
|
if date_str.include?("/")
|
|
@@ -108,6 +131,40 @@ module Playbook
|
|
|
108
131
|
end
|
|
109
132
|
end
|
|
110
133
|
|
|
134
|
+
# Parses timed custom boundaries. Mirrors React parseQuickPickDateTime:
|
|
135
|
+
# 1) US m/d/Y + time (optional :SS / AM|PM) → DateTime.civil (wall-clock)
|
|
136
|
+
# 2) Offset-less YYYY-MM-DDTHH:MM:SS → DateTime.civil (wall-clock; not Time.parse)
|
|
137
|
+
# 3) ISO with Z / numeric offset → DateTime.iso8601 (absolute; emit keeps offset)
|
|
138
|
+
# Unsupported timed strings raise — no process-TZ Time.parse fallback.
|
|
139
|
+
# Date-only boundaries stay on parse_date_string (unchanged).
|
|
140
|
+
def parse_datetime_string(date_str)
|
|
141
|
+
trimmed = date_str.to_s.strip
|
|
142
|
+
|
|
143
|
+
if (match = trimmed.match(%r{\A(\d{1,2})/(\d{1,2})/(\d{4})\s+(\d{1,2}):(\d{2})(?::(\d{2}))?\s*(AM|PM)?\z}i))
|
|
144
|
+
month, day, year, hour, min, sec, meridiem = match.captures
|
|
145
|
+
hour = hour.to_i
|
|
146
|
+
min = min.to_i
|
|
147
|
+
sec = (sec || 0).to_i
|
|
148
|
+
if meridiem
|
|
149
|
+
meridiem = meridiem.upcase
|
|
150
|
+
hour = 0 if meridiem == "AM" && hour == 12
|
|
151
|
+
hour += 12 if meridiem == "PM" && hour != 12
|
|
152
|
+
end
|
|
153
|
+
return DateTime.civil(year.to_i, month.to_i, day.to_i, hour, min, sec)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Offset-less wall-clock ISO (same shape as WALL_CLOCK_ISO in quickpickDateSync.ts).
|
|
157
|
+
if (match = trimmed.match(/\A(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?(?:\.\d+)?\z/))
|
|
158
|
+
year, month, day, hour, min, sec = match.captures
|
|
159
|
+
return DateTime.civil(year.to_i, month.to_i, day.to_i, hour.to_i, min.to_i, (sec || 0).to_i)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Absolute ISO with Z or numeric offset (React: new Date(iso)).
|
|
163
|
+
return DateTime.iso8601(trimmed).extend(AbsoluteInstant) if trimmed.match?(/\A\d{4}-\d{2}-\d{2}T/) && trimmed.match?(/[Zz]|[+-]\d{2}:?\d{2}\z/)
|
|
164
|
+
|
|
165
|
+
raise ArgumentError, "Unsupported QuickPick timed value: #{date_str.inspect}"
|
|
166
|
+
end
|
|
167
|
+
|
|
111
168
|
def calculate_start_date(time_period, amount, end_date)
|
|
112
169
|
case time_period.to_s
|
|
113
170
|
when "days"
|
|
@@ -125,8 +182,40 @@ module Playbook
|
|
|
125
182
|
end
|
|
126
183
|
end
|
|
127
184
|
|
|
185
|
+
# Date-only → m/d/Y (SOD/EOD applied at sync when enableTime).
|
|
186
|
+
# Wall-clock Time/DateTime → offset-less YYYY-MM-DDTHH:MM:SS (local clock face).
|
|
187
|
+
# Absolute ISO (AbsoluteInstant) → iso8601 with Z/±HH:MM so JS new Date keeps
|
|
188
|
+
# the same instant (React parseQuickPickDateTime already handles both).
|
|
128
189
|
def format_date(date)
|
|
129
|
-
date
|
|
190
|
+
if time_like?(date)
|
|
191
|
+
format_timed(date)
|
|
192
|
+
else
|
|
193
|
+
date.strftime("%m/%d/%Y")
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def format_value(date)
|
|
198
|
+
if time_like?(date)
|
|
199
|
+
format_timed(date)
|
|
200
|
+
else
|
|
201
|
+
date.to_s
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def format_timed(date)
|
|
206
|
+
if absolute_instant?(date)
|
|
207
|
+
date.iso8601
|
|
208
|
+
else
|
|
209
|
+
date.strftime("%Y-%m-%dT%H:%M:%S")
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def absolute_instant?(date)
|
|
214
|
+
date.respond_to?(:absolute_instant?) && date.absolute_instant?
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def time_like?(date)
|
|
218
|
+
date.is_a?(Time) || date.is_a?(DateTime) || defined?(ActiveSupport::TimeWithZone) && date.is_a?(ActiveSupport::TimeWithZone)
|
|
130
219
|
end
|
|
131
220
|
|
|
132
221
|
def format_date_range(start_date, end_date)
|
|
@@ -1,2 +1,9 @@
|
|
|
1
1
|
export { separateChildComponents, prepareSubcomponents } from './subComponentHelper';
|
|
2
|
-
export { handleClickOutside } from './clickOutsideHelper';
|
|
2
|
+
export { handleClickOutside } from './clickOutsideHelper';
|
|
3
|
+
export {
|
|
4
|
+
endOfDay,
|
|
5
|
+
parseQuickPickDateOnly,
|
|
6
|
+
setQuickPickDateOnPicker,
|
|
7
|
+
startOfDay,
|
|
8
|
+
stringHasExplicitTime,
|
|
9
|
+
} from './quickpickDateSync';
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// QuickPick → DatePicker sync helpers.
|
|
2
|
+
// End-of-day uses 23:59:00 to match DatePicker enableTime minute precision
|
|
3
|
+
// (default timeFormat has no seconds).
|
|
4
|
+
//
|
|
5
|
+
// Contract when the target Flatpickr has enableTime:
|
|
6
|
+
// - Date-only strings (e.g. m/d/Y) → start of day / end of day by bound
|
|
7
|
+
// - Timed strings → parse to Date and pass through unchanged
|
|
8
|
+
// - Date objects → pass through unchanged (presets already SOD/EOD via toQuickPickRange;
|
|
9
|
+
// custom values may intentionally use midnight or 23:59:00)
|
|
10
|
+
|
|
11
|
+
type FlatpickrLike = {
|
|
12
|
+
setDate: (date: Date | string, triggerChange?: boolean, format?: string) => void
|
|
13
|
+
config?: { enableTime?: boolean }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type QuickPickDateBound = "start" | "end"
|
|
17
|
+
|
|
18
|
+
const DATE_ONLY_MDY = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/
|
|
19
|
+
// Mirrors Rails QuickpickHelper#parse_datetime_string for US m/d/Y + optional AM/PM.
|
|
20
|
+
const MDY_WITH_TIME =
|
|
21
|
+
/^(\d{1,2})\/(\d{1,2})\/(\d{4})\s+(\d{1,2}):(\d{2})(?::(\d{2}))?\s*(AM|PM)?$/i
|
|
22
|
+
// Offset-less wall-clock from Rails format_date / format_value (no Z / ±HH:MM).
|
|
23
|
+
const WALL_CLOCK_ISO =
|
|
24
|
+
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?(?:\.\d+)?$/
|
|
25
|
+
|
|
26
|
+
export const startOfDay = (date: Date): Date => {
|
|
27
|
+
const next = new Date(date.getTime())
|
|
28
|
+
next.setHours(0, 0, 0, 0)
|
|
29
|
+
return next
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const endOfDay = (date: Date): Date => {
|
|
33
|
+
const next = new Date(date.getTime())
|
|
34
|
+
next.setHours(23, 59, 0, 0)
|
|
35
|
+
return next
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const stringHasExplicitTime = (value: string): boolean => {
|
|
39
|
+
return /[T\s]\d{1,2}:\d{2}/.test(value) || /\d{1,2}:\d{2}\s*(AM|PM)/i.test(value)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const parseQuickPickDateOnly = (value: string): Date | null => {
|
|
43
|
+
const match = value.trim().match(DATE_ONLY_MDY)
|
|
44
|
+
if (!match) return null
|
|
45
|
+
const month = Number(match[1])
|
|
46
|
+
const day = Number(match[2])
|
|
47
|
+
const year = Number(match[3])
|
|
48
|
+
return new Date(year, month - 1, day)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Parse timed QuickPick custom strings to a local Date.
|
|
53
|
+
* - m/d/Y + time (optional seconds / AM|PM) → wall-clock components (Safari-safe)
|
|
54
|
+
* - Offset-less YYYY-MM-DDTHH:MM:SS → wall-clock components
|
|
55
|
+
* - ISO with Z / offset → absolute instant via Date constructor
|
|
56
|
+
*/
|
|
57
|
+
export const parseQuickPickDateTime = (value: string): Date | null => {
|
|
58
|
+
const trimmed = value.trim()
|
|
59
|
+
|
|
60
|
+
const mdy = trimmed.match(MDY_WITH_TIME)
|
|
61
|
+
if (mdy) {
|
|
62
|
+
const month = Number(mdy[1])
|
|
63
|
+
const day = Number(mdy[2])
|
|
64
|
+
const year = Number(mdy[3])
|
|
65
|
+
let hour = Number(mdy[4])
|
|
66
|
+
const minute = Number(mdy[5])
|
|
67
|
+
const second = mdy[6] != null ? Number(mdy[6]) : 0
|
|
68
|
+
const meridiem = mdy[7]?.toUpperCase()
|
|
69
|
+
if (meridiem === "AM" && hour === 12) hour = 0
|
|
70
|
+
if (meridiem === "PM" && hour !== 12) hour += 12
|
|
71
|
+
return new Date(year, month - 1, day, hour, minute, second)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const wallClock = trimmed.match(WALL_CLOCK_ISO)
|
|
75
|
+
if (wallClock) {
|
|
76
|
+
const year = Number(wallClock[1])
|
|
77
|
+
const month = Number(wallClock[2])
|
|
78
|
+
const day = Number(wallClock[3])
|
|
79
|
+
const hour = Number(wallClock[4])
|
|
80
|
+
const minute = Number(wallClock[5])
|
|
81
|
+
const second = wallClock[6] != null ? Number(wallClock[6]) : 0
|
|
82
|
+
return new Date(year, month - 1, day, hour, minute, second)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const parsed = new Date(trimmed)
|
|
86
|
+
if (Number.isNaN(parsed.getTime())) return null
|
|
87
|
+
return parsed
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Apply a QuickPick date to a Flatpickr instance.
|
|
92
|
+
* With enableTime and a date-only string: start → 00:00:00, end → 23:59:00.
|
|
93
|
+
* Timed strings and Date values are passed through unchanged.
|
|
94
|
+
* Date-only pickers keep the existing m/d/Y string path for date-only values.
|
|
95
|
+
*/
|
|
96
|
+
export const setQuickPickDateOnPicker = (
|
|
97
|
+
picker: FlatpickrLike | null | undefined,
|
|
98
|
+
value: Date | string | null | undefined,
|
|
99
|
+
bound: QuickPickDateBound,
|
|
100
|
+
): void => {
|
|
101
|
+
if (!picker || value == null || value === "") return
|
|
102
|
+
|
|
103
|
+
const enableTime = Boolean(picker.config?.enableTime)
|
|
104
|
+
|
|
105
|
+
if (!enableTime) {
|
|
106
|
+
if (typeof value === "string") {
|
|
107
|
+
// Timed payloads (ISO / datetime) are not valid for Flatpickr's m/d/Y format.
|
|
108
|
+
if (stringHasExplicitTime(value)) {
|
|
109
|
+
const parsed = parseQuickPickDateTime(value)
|
|
110
|
+
if (!parsed) return
|
|
111
|
+
picker.setDate(parsed, true)
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
picker.setDate(value, true, "m/d/Y")
|
|
115
|
+
} else {
|
|
116
|
+
picker.setDate(value, true)
|
|
117
|
+
}
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (typeof value === "string") {
|
|
122
|
+
if (stringHasExplicitTime(value)) {
|
|
123
|
+
const parsed = parseQuickPickDateTime(value)
|
|
124
|
+
if (!parsed) return
|
|
125
|
+
picker.setDate(parsed, true)
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let date = parseQuickPickDateOnly(value) ?? new Date(value)
|
|
130
|
+
if (Number.isNaN(date.getTime())) return
|
|
131
|
+
date = bound === "start" ? startOfDay(date) : endOfDay(date)
|
|
132
|
+
picker.setDate(date, true)
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
picker.setDate(value, true)
|
|
137
|
+
}
|
|
@@ -28,7 +28,7 @@ export type DropdownInteractiveConfig = {
|
|
|
28
28
|
override?: boolean,
|
|
29
29
|
dates: {
|
|
30
30
|
label: string,
|
|
31
|
-
value: string
|
|
31
|
+
value: Array<Date | string> | { timePeriod: string, amount: number },
|
|
32
32
|
}[],
|
|
33
33
|
},
|
|
34
34
|
value?: string,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import classnames from 'classnames'
|
|
3
3
|
import { globalProps, GlobalProps } from '../utilities/globalProps'
|
|
4
|
+
import { globalEventProps, GlobalEventProps } from '../utilities/globalEventProps'
|
|
4
5
|
import { buildDataProps, buildHtmlProps } from '../utilities/props'
|
|
5
6
|
import { findHighlightChunks } from './_highlightChunks'
|
|
6
7
|
|
|
@@ -12,7 +13,7 @@ type HighlightProps = {
|
|
|
12
13
|
children?: React.ReactChild[] | React.ReactChild | string,
|
|
13
14
|
text?: string,
|
|
14
15
|
highlightedText?: string[],
|
|
15
|
-
} & GlobalProps
|
|
16
|
+
} & GlobalProps & GlobalEventProps
|
|
16
17
|
|
|
17
18
|
const Highlight = (props: HighlightProps): React.ReactElement => {
|
|
18
19
|
const {
|
|
@@ -35,6 +36,7 @@ const Highlight = (props: HighlightProps): React.ReactElement => {
|
|
|
35
36
|
<span
|
|
36
37
|
{...dataProps}
|
|
37
38
|
{...htmlProps}
|
|
39
|
+
{...globalEventProps(props)}
|
|
38
40
|
id={id}
|
|
39
41
|
>
|
|
40
42
|
{chunks.map((chunk, index) => {
|
|
@@ -3,6 +3,7 @@ import classnames from 'classnames'
|
|
|
3
3
|
|
|
4
4
|
import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
|
|
5
5
|
import { globalProps, GlobalProps } from '../utilities/globalProps'
|
|
6
|
+
import { GlobalEventProps, globalEventProps } from '../utilities/globalEventProps'
|
|
6
7
|
|
|
7
8
|
import Body from '../pb_body/_body'
|
|
8
9
|
import Caption from '../pb_caption/_caption'
|
|
@@ -33,7 +34,7 @@ type IconStatValueProps = {
|
|
|
33
34
|
| "yellow"
|
|
34
35
|
| "orange"
|
|
35
36
|
| "green"
|
|
36
|
-
} & GlobalProps
|
|
37
|
+
} & GlobalProps & GlobalEventProps
|
|
37
38
|
|
|
38
39
|
const IconStatValue = (props: IconStatValueProps): React.ReactElement => {
|
|
39
40
|
const {
|
|
@@ -94,6 +95,7 @@ const IconStatValue = (props: IconStatValueProps): React.ReactElement => {
|
|
|
94
95
|
{...ariaProps}
|
|
95
96
|
{...dataProps}
|
|
96
97
|
{...htmlProps}
|
|
98
|
+
{...globalEventProps(props)}
|
|
97
99
|
className={classes}
|
|
98
100
|
id={id}
|
|
99
101
|
>
|
|
@@ -3,6 +3,7 @@ import classnames from 'classnames'
|
|
|
3
3
|
|
|
4
4
|
import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
|
|
5
5
|
import { globalProps } from '../utilities/globalProps'
|
|
6
|
+
import { GlobalEventProps, globalEventProps } from '../utilities/globalEventProps'
|
|
6
7
|
|
|
7
8
|
import Body from '../pb_body/_body'
|
|
8
9
|
import Icon from '../pb_icon/_icon'
|
|
@@ -18,7 +19,7 @@ type IconValueProps = {
|
|
|
18
19
|
htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
|
|
19
20
|
id?: string,
|
|
20
21
|
text: string,
|
|
21
|
-
}
|
|
22
|
+
} & GlobalEventProps
|
|
22
23
|
|
|
23
24
|
const IconValue = (props: IconValueProps): React.ReactElement => {
|
|
24
25
|
const {
|
|
@@ -46,6 +47,7 @@ const IconValue = (props: IconValueProps): React.ReactElement => {
|
|
|
46
47
|
{...ariaProps}
|
|
47
48
|
{...dataProps}
|
|
48
49
|
{...htmlProps}
|
|
50
|
+
{...globalEventProps(props)}
|
|
49
51
|
className={classes}
|
|
50
52
|
id={id}
|
|
51
53
|
>
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
import classnames from "classnames";
|
|
3
3
|
import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
|
|
4
4
|
import { globalProps } from "../utilities/globalProps";
|
|
5
|
+
import { GlobalEventProps, globalEventProps } from "../utilities/globalEventProps";
|
|
5
6
|
import DateTime from '../pb_kit/dateTime';
|
|
6
7
|
|
|
7
8
|
import Body from "../pb_body/_body";
|
|
@@ -25,7 +26,7 @@ type LabelValueProps = {
|
|
|
25
26
|
icon?: string;
|
|
26
27
|
description?: string;
|
|
27
28
|
title?: string;
|
|
28
|
-
};
|
|
29
|
+
} & GlobalEventProps;
|
|
29
30
|
|
|
30
31
|
const dateString = (value: Date) => {
|
|
31
32
|
const month = DateTime.toMonthNum(value);
|
|
@@ -67,6 +68,7 @@ const LabelValue = (props: LabelValueProps) => {
|
|
|
67
68
|
{...ariaProps}
|
|
68
69
|
{...dataProps}
|
|
69
70
|
{...htmlProps}
|
|
71
|
+
{...globalEventProps(props)}
|
|
70
72
|
className={classes}
|
|
71
73
|
id={id}
|
|
72
74
|
title={title}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
This kit provides a wrapping class to place around the MapLibre library. Complete docs for using the library can be found [here](https://maplibre.org/maplibre-gl-js-docs/api/).
|
|
2
2
|
|
|
3
3
|
Basic setup to start using MapLibre:
|
|
4
|
-
- Install the npm package using `yarn add maplibre-gl`
|
|
5
|
-
- To include the maplibre css, include a link to the CSS file as a CDN in your stylesheet using the following syntax: `@import url("https://unpkg.com/maplibre-gl@6.
|
|
6
|
-
OR include it as a link in the <head> tag `<link href='https://unpkg.com/maplibre-gl@6.
|
|
4
|
+
- Install the npm package using `yarn add maplibre-gl@6.4.1`
|
|
5
|
+
- To include the maplibre css, include a link to the CSS file as a CDN in your stylesheet using the following syntax: `@import url("https://unpkg.com/maplibre-gl@6.4.1/dist/maplibre-gl.css");`
|
|
6
|
+
OR include it as a link in the <head> tag `<link href='https://unpkg.com/maplibre-gl@6.4.1/dist/maplibre-gl.css' rel='stylesheet' />`
|
|
7
7
|
- You can now use MapLibre within the Map Kit as shown in this example.
|
|
8
8
|
|
|
9
9
|
__Notes__ :
|
|
@@ -3,6 +3,7 @@ import classnames from 'classnames'
|
|
|
3
3
|
|
|
4
4
|
import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
|
|
5
5
|
import { globalProps } from '../utilities/globalProps'
|
|
6
|
+
import { GlobalEventProps, globalEventProps } from '../utilities/globalEventProps'
|
|
6
7
|
|
|
7
8
|
import Avatar from '../pb_avatar/_avatar'
|
|
8
9
|
import Body from '../pb_body/_body'
|
|
@@ -28,7 +29,7 @@ type MessageProps = {
|
|
|
28
29
|
timestampObject?: Date,
|
|
29
30
|
timezone?: string,
|
|
30
31
|
alignTimestamp?: string,
|
|
31
|
-
}
|
|
32
|
+
} & GlobalEventProps
|
|
32
33
|
|
|
33
34
|
const Message = (props: MessageProps) => {
|
|
34
35
|
const {
|
|
@@ -68,6 +69,7 @@ const Message = (props: MessageProps) => {
|
|
|
68
69
|
{...ariaProps}
|
|
69
70
|
{...dataProps}
|
|
70
71
|
{...htmlProps}
|
|
72
|
+
{...globalEventProps(props)}
|
|
71
73
|
className={classes}
|
|
72
74
|
id={id}
|
|
73
75
|
>
|
|
@@ -3,6 +3,7 @@ import classnames from 'classnames'
|
|
|
3
3
|
|
|
4
4
|
import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
|
|
5
5
|
import { globalProps } from '../utilities/globalProps'
|
|
6
|
+
import { GlobalEventProps, globalEventProps } from '../utilities/globalEventProps'
|
|
6
7
|
|
|
7
8
|
import Avatar from '../pb_avatar/_avatar'
|
|
8
9
|
import Tooltip from '../pb_tooltip/_tooltip'
|
|
@@ -19,7 +20,7 @@ type MultipleUsersProps = {
|
|
|
19
20
|
size?: "md" | "lg" | "sm" | "xl" | "xs" | "xxs",
|
|
20
21
|
withTooltip?: boolean,
|
|
21
22
|
users: Array<{ [key: string]: string }>,
|
|
22
|
-
}
|
|
23
|
+
} & GlobalEventProps
|
|
23
24
|
|
|
24
25
|
const MultipleUsers = (props: MultipleUsersProps): React.ReactElement => {
|
|
25
26
|
const {
|
|
@@ -126,6 +127,7 @@ const MultipleUsers = (props: MultipleUsersProps): React.ReactElement => {
|
|
|
126
127
|
{...ariaProps}
|
|
127
128
|
{...dataProps}
|
|
128
129
|
{...htmlProps}
|
|
130
|
+
{...globalEventProps(props)}
|
|
129
131
|
className={classes}
|
|
130
132
|
id={id}
|
|
131
133
|
>
|