phlex_kit 0.11.0 → 0.12.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/components/phlex_kit/alert_dialog/alert_dialog.css +3 -1
- data/app/components/phlex_kit/alert_dialog/alert_dialog_content.rb +13 -2
- data/app/components/phlex_kit/alert_dialog/alert_dialog_controller.js +35 -7
- data/app/components/phlex_kit/attachment/attachment.css +15 -0
- data/app/components/phlex_kit/attachment/attachment_trigger.rb +3 -0
- data/app/components/phlex_kit/breadcrumb/breadcrumb.css +1 -0
- data/app/components/phlex_kit/calendar/calendar_controller.js +23 -6
- data/app/components/phlex_kit/carousel/carousel_controller.js +36 -2
- data/app/components/phlex_kit/chart/chart.rb +6 -4
- data/app/components/phlex_kit/chart/chart_controller.js +37 -8
- data/app/components/phlex_kit/codeblock/codeblock.rb +5 -1
- data/app/components/phlex_kit/combobox/combobox.css +1 -1
- data/app/components/phlex_kit/combobox/combobox_controller.js +57 -2
- data/app/components/phlex_kit/command/command_controller.js +17 -1
- data/app/components/phlex_kit/command/command_input.rb +3 -2
- data/app/components/phlex_kit/context_menu/context_menu.css +3 -0
- data/app/components/phlex_kit/context_menu/context_menu.rb +9 -1
- data/app/components/phlex_kit/context_menu/context_menu_controller.js +49 -12
- data/app/components/phlex_kit/data_table/data_table.css +1 -1
- data/app/components/phlex_kit/data_table/data_table_pagination.rb +4 -1
- data/app/components/phlex_kit/data_table/data_table_per_page_select.rb +8 -3
- data/app/components/phlex_kit/data_table/data_table_search.rb +7 -2
- data/app/components/phlex_kit/date_picker/date_picker.rb +13 -2
- data/app/components/phlex_kit/date_picker/date_picker_controller.js +28 -0
- data/app/components/phlex_kit/dialog/dialog_controller.js +3 -0
- data/app/components/phlex_kit/drawer/drawer.rb +1 -1
- data/app/components/phlex_kit/drawer/drawer_content.rb +10 -3
- data/app/components/phlex_kit/dropdown_menu/dropdown_menu.css +4 -0
- data/app/components/phlex_kit/dropdown_menu/dropdown_menu.rb +3 -1
- data/app/components/phlex_kit/dropdown_menu/dropdown_menu_controller.js +54 -13
- data/app/components/phlex_kit/form_field/form_field_controller.js +32 -24
- data/app/components/phlex_kit/hover_card/hover_card.css +6 -0
- data/app/components/phlex_kit/hover_card/hover_card_controller.js +24 -0
- data/app/components/phlex_kit/input/input.css +0 -1
- data/app/components/phlex_kit/input_otp/input_otp.rb +6 -3
- data/app/components/phlex_kit/input_otp/input_otp_controller.js +24 -2
- data/app/components/phlex_kit/item/item.css +2 -1
- data/app/components/phlex_kit/kbd/kbd.css +2 -1
- data/app/components/phlex_kit/label/label.css +1 -1
- data/app/components/phlex_kit/link/link.rb +1 -0
- data/app/components/phlex_kit/marker/marker.css +2 -1
- data/app/components/phlex_kit/menubar/menubar.css +3 -0
- data/app/components/phlex_kit/menubar/menubar_controller.js +40 -16
- data/app/components/phlex_kit/native_select/native_select.css +14 -0
- data/app/components/phlex_kit/navigation_menu/navigation_menu_link.rb +8 -1
- data/app/components/phlex_kit/popover/popover_controller.js +19 -0
- data/app/components/phlex_kit/scroll_area/scroll_area.rb +1 -14
- data/app/components/phlex_kit/select/select_controller.js +22 -0
- data/app/components/phlex_kit/select/select_trigger.rb +4 -1
- data/app/components/phlex_kit/sheet/sheet_content.rb +13 -3
- data/app/components/phlex_kit/sheet/sheet_content_controller.js +36 -0
- data/app/components/phlex_kit/sheet/sheet_controller.js +17 -2
- data/app/components/phlex_kit/spinner/spinner.rb +6 -3
- data/app/components/phlex_kit/switch/switch.rb +6 -0
- data/app/components/phlex_kit/tabs/tabs_controller.js +8 -2
- data/app/components/phlex_kit/toast/toast_action.rb +1 -1
- data/app/components/phlex_kit/toast/toast_close.rb +6 -3
- data/app/components/phlex_kit/toast/toast_controller.js +32 -16
- data/app/components/phlex_kit/toast/toast_item.rb +11 -7
- data/app/components/phlex_kit/toast/toast_region.rb +12 -3
- data/app/components/phlex_kit/toast/toaster_controller.js +2 -0
- data/app/components/phlex_kit/toggle_group/toggle_group.rb +16 -1
- data/app/components/phlex_kit/toggle_group/toggle_group_controller.js +11 -8
- data/app/components/phlex_kit/toggle_group/toggle_group_item.rb +15 -5
- data/app/javascript/phlex_kit/controllers/index.js +2 -0
- data/lib/phlex_kit/base_component.rb +13 -3
- data/lib/phlex_kit/version.rb +1 -1
- data/lib/phlex_kit.rb +1 -0
- metadata +2 -1
|
@@ -10,6 +10,12 @@ module PhlexKit
|
|
|
10
10
|
class ToastRegion < BaseComponent
|
|
11
11
|
SKELETON_VARIANTS = %i[default success error warning info loading].freeze
|
|
12
12
|
|
|
13
|
+
# Sentinel default for dir: — distinguishes "caller didn't pass dir:" (omit
|
|
14
|
+
# the attribute, inherit from the page) from an explicit dir: :ltr (must
|
|
15
|
+
# render dir="ltr"), which a plain `:ltr` default can't tell apart.
|
|
16
|
+
DIR_UNSET = Object.new.freeze
|
|
17
|
+
private_constant :DIR_UNSET
|
|
18
|
+
|
|
13
19
|
POSITIONS = {
|
|
14
20
|
top_left: "top-left",
|
|
15
21
|
top_center: "top-center",
|
|
@@ -30,7 +36,7 @@ module PhlexKit
|
|
|
30
36
|
rich_colors: false,
|
|
31
37
|
close_button: false,
|
|
32
38
|
hotkey: %w[alt t],
|
|
33
|
-
dir:
|
|
39
|
+
dir: DIR_UNSET,
|
|
34
40
|
flash: nil,
|
|
35
41
|
id: "pk-toaster",
|
|
36
42
|
**attrs
|
|
@@ -53,7 +59,8 @@ module PhlexKit
|
|
|
53
59
|
end
|
|
54
60
|
@close_button = close_button
|
|
55
61
|
@hotkey = hotkey
|
|
56
|
-
@
|
|
62
|
+
@dir_explicit = !dir.equal?(DIR_UNSET)
|
|
63
|
+
@dir = (@dir_explicit ? dir : :ltr).to_sym
|
|
57
64
|
unless %i[ltr rtl auto].include?(@dir)
|
|
58
65
|
raise ArgumentError, "ToastRegion dir: must be :ltr, :rtl or :auto"
|
|
59
66
|
end
|
|
@@ -138,7 +145,9 @@ module PhlexKit
|
|
|
138
145
|
phlex_kit__toaster_hotkey_value: Array(@hotkey).join("+")
|
|
139
146
|
}
|
|
140
147
|
}
|
|
141
|
-
|
|
148
|
+
# Only an explicit dir: renders the attribute — the true default (no
|
|
149
|
+
# dir: passed) omits it so the toast inherits the page's direction.
|
|
150
|
+
base[:dir] = @dir.to_s if @dir_explicit
|
|
142
151
|
base
|
|
143
152
|
end
|
|
144
153
|
end
|
|
@@ -172,6 +172,7 @@ export default class extends Controller {
|
|
|
172
172
|
)
|
|
173
173
|
return
|
|
174
174
|
}
|
|
175
|
+
if (!this._listEl) return
|
|
175
176
|
const el = this._listEl.querySelector(`#${CSS.escape(id)}`)
|
|
176
177
|
if (el) el.dispatchEvent(new CustomEvent("phlex-kit:toast:force-dismiss", { bubbles: true }))
|
|
177
178
|
}
|
|
@@ -329,6 +330,7 @@ export default class extends Controller {
|
|
|
329
330
|
}
|
|
330
331
|
|
|
331
332
|
_mutate(id, variant, text) {
|
|
333
|
+
if (!this._listEl) return
|
|
332
334
|
const el = this._listEl.querySelector(`#${CSS.escape(id)}`)
|
|
333
335
|
if (!el) return
|
|
334
336
|
el.dataset.variant = variant
|
|
@@ -28,13 +28,28 @@ module PhlexKit
|
|
|
28
28
|
|
|
29
29
|
def item_context
|
|
30
30
|
{ type: @type, variant: @variant, size: @size, disabled: @disabled,
|
|
31
|
-
selected_values: selected_values, spacing: @spacing, orientation: @orientation
|
|
31
|
+
selected_values: selected_values, spacing: @spacing, orientation: @orientation,
|
|
32
|
+
group: self }
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
def ToggleGroupItem(**kwargs, &block)
|
|
35
36
|
render PhlexKit::ToggleGroupItem.new(group_context: item_context, **kwargs), &block
|
|
36
37
|
end
|
|
37
38
|
|
|
39
|
+
# Roving-tabindex initial stop (single-type, nothing selected): the FIRST
|
|
40
|
+
# enabled item claims tabindex="0" server-side, mirroring what
|
|
41
|
+
# toggle_group_controller.js's reconcile() computes at runtime
|
|
42
|
+
# (`pressed || enabledItems()[0]`). Items call this once each, in render
|
|
43
|
+
# order, as they're constructed — a single-threaded sequential claim, not
|
|
44
|
+
# a lookahead over siblings not yet rendered.
|
|
45
|
+
def claim_tab_stop(item_disabled)
|
|
46
|
+
return false unless selected_values.empty?
|
|
47
|
+
return false if item_disabled
|
|
48
|
+
return false if @tab_stop_claimed
|
|
49
|
+
@tab_stop_claimed = true
|
|
50
|
+
true
|
|
51
|
+
end
|
|
52
|
+
|
|
38
53
|
private
|
|
39
54
|
|
|
40
55
|
def selected_values
|
|
@@ -33,14 +33,17 @@ export default class extends Controller {
|
|
|
33
33
|
if (items.length === 0) return
|
|
34
34
|
const currentIndex = items.indexOf(event.currentTarget)
|
|
35
35
|
let nextIndex = currentIndex
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
// In RTL the horizontal arrows mirror (physical LEFT = next); Up/Down are
|
|
37
|
+
// unaffected. Runtime dir check is reliable after a dynamic flip.
|
|
38
|
+
const rtl = getComputedStyle(this.element).direction === "rtl"
|
|
39
|
+
const fwd = rtl ? "ArrowLeft" : "ArrowRight"
|
|
40
|
+
const back = rtl ? "ArrowRight" : "ArrowLeft"
|
|
41
|
+
if (event.key === fwd || event.key === "ArrowDown") nextIndex = (currentIndex + 1) % items.length
|
|
42
|
+
else if (event.key === back || event.key === "ArrowUp") nextIndex = (currentIndex - 1 + items.length) % items.length
|
|
43
|
+
else if (event.key === "Home") nextIndex = 0
|
|
44
|
+
else if (event.key === "End") nextIndex = items.length - 1
|
|
45
|
+
else if (event.key === " " || event.key === "Enter") { event.preventDefault(); event.currentTarget.click(); return }
|
|
46
|
+
else return
|
|
44
47
|
event.preventDefault()
|
|
45
48
|
const next = items[nextIndex]
|
|
46
49
|
this.updateRovingTabindex(next)
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
module PhlexKit
|
|
2
2
|
class ToggleGroupItem < Toggle
|
|
3
3
|
def initialize(value:, group_context:, variant: nil, size: nil, **attrs)
|
|
4
|
-
# Toggle kwargs this item renders no markup for
|
|
5
|
-
#
|
|
6
|
-
|
|
4
|
+
# Toggle kwargs this item renders no markup for, or that the group
|
|
5
|
+
# derives itself (pressed: comes from the group's selected_values) —
|
|
6
|
+
# inheriting them silently discarded the caller's input.
|
|
7
|
+
unsupported = attrs.keys & %i[wrapper name unpressed_value pressed]
|
|
7
8
|
if unsupported.any?
|
|
8
9
|
raise ArgumentError, "ToggleGroupItem does not support #{unsupported.join(", ")} (group items render a bare button)"
|
|
9
10
|
end
|
|
10
11
|
@item_value = value.to_s
|
|
11
12
|
@group_context = group_context
|
|
12
13
|
pressed = group_context[:selected_values].include?(@item_value)
|
|
14
|
+
item_disabled = attrs.key?(:disabled) ? attrs.delete(:disabled) : group_context[:disabled]
|
|
15
|
+
# Roving tabindex initial stop: when nothing is selected yet, the first
|
|
16
|
+
# enabled item claims tabindex="0" (see ToggleGroup#claim_tab_stop).
|
|
17
|
+
# group_context[:group] is nil for a hand-built context (bypassing
|
|
18
|
+
# ToggleGroup#item_context) — treat that as "no tab-stop claim" rather
|
|
19
|
+
# than raising, since standalone tests construct contexts by hand.
|
|
20
|
+
@is_first_tab_stop = group_context[:group]&.claim_tab_stop(item_disabled) || false
|
|
13
21
|
super(pressed: pressed, name: nil, value: @item_value,
|
|
14
22
|
variant: variant || group_context[:variant],
|
|
15
23
|
size: size || group_context[:size],
|
|
16
|
-
disabled:
|
|
24
|
+
disabled: item_disabled, **attrs)
|
|
17
25
|
end
|
|
18
26
|
|
|
19
27
|
def view_template(&block)
|
|
@@ -34,7 +42,9 @@ module PhlexKit
|
|
|
34
42
|
a[:aria] = { checked: @pressed.to_s }
|
|
35
43
|
# A disabled button can't take focus — giving the tab stop to a
|
|
36
44
|
# pressed-but-disabled item made the whole group Tab-unreachable.
|
|
37
|
-
|
|
45
|
+
# When nothing is selected, the first enabled item claims the initial
|
|
46
|
+
# roving-tabindex stop instead of every item defaulting to -1.
|
|
47
|
+
a[:tabindex] = (@pressed && !@disabled) || @is_first_tab_stop ? "0" : "-1"
|
|
38
48
|
else
|
|
39
49
|
a[:aria] = { pressed: @pressed.to_s }
|
|
40
50
|
a[:tabindex] = "0"
|
|
@@ -24,6 +24,7 @@ import ContextMenuController from "phlex_kit/controllers/context_menu_controller
|
|
|
24
24
|
import DataTableController from "phlex_kit/controllers/data_table_controller"
|
|
25
25
|
import DataTableColumnVisibilityController from "phlex_kit/controllers/data_table_column_visibility_controller"
|
|
26
26
|
import DataTableSearchController from "phlex_kit/controllers/data_table_search_controller"
|
|
27
|
+
import DatePickerController from "phlex_kit/controllers/date_picker_controller"
|
|
27
28
|
import DialogController from "phlex_kit/controllers/dialog_controller"
|
|
28
29
|
import DropdownMenuController from "phlex_kit/controllers/dropdown_menu_controller"
|
|
29
30
|
import FormFieldController from "phlex_kit/controllers/form_field_controller"
|
|
@@ -65,6 +66,7 @@ export function registerPhlexKitControllers(application) {
|
|
|
65
66
|
application.register("phlex-kit--data-table", DataTableController)
|
|
66
67
|
application.register("phlex-kit--data-table-column-visibility", DataTableColumnVisibilityController)
|
|
67
68
|
application.register("phlex-kit--data-table-search", DataTableSearchController)
|
|
69
|
+
application.register("phlex-kit--date-picker", DatePickerController)
|
|
68
70
|
application.register("phlex-kit--dialog", DialogController)
|
|
69
71
|
application.register("phlex-kit--dropdown-menu", DropdownMenuController)
|
|
70
72
|
application.register("phlex-kit--form-field", FormFieldController)
|
|
@@ -36,12 +36,22 @@ module PhlexKit
|
|
|
36
36
|
# generated default label must skip it then: `mix` merges duplicate string
|
|
37
37
|
# attrs ("pagination Résultats") instead of overriding.
|
|
38
38
|
def aria_labelled?
|
|
39
|
+
aria_key_set?(:label) || aria_key_set?(:labelledby)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# True when the caller already supplied their own value for a given aria
|
|
43
|
+
# attribute — via the aria: hash (aria: { <key>: ... }) or the flat
|
|
44
|
+
# "aria-<key>"/aria_<key> spelling. A component with a generated default
|
|
45
|
+
# for that attribute must skip it then: `mix` merges duplicate attrs
|
|
46
|
+
# (aria-modal="true false") instead of overriding.
|
|
47
|
+
def aria_key_set?(key)
|
|
39
48
|
aria = @attrs[:aria] || @attrs["aria"]
|
|
40
49
|
if aria.is_a?(Hash)
|
|
41
|
-
return true if
|
|
50
|
+
return true if aria.key?(key) || aria.key?(key.to_s)
|
|
42
51
|
end
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
dashed = "aria-#{key}"
|
|
53
|
+
underscored = "aria_#{key}"
|
|
54
|
+
[ dashed.to_sym, dashed, underscored.to_sym, underscored ].any? { |k| @attrs[k] }
|
|
45
55
|
end
|
|
46
56
|
end
|
|
47
57
|
end
|
data/lib/phlex_kit/version.rb
CHANGED
data/lib/phlex_kit.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "json" # Carousel serializes its options value standalone (no Rails to_json)
|
|
4
4
|
require "securerandom" # DatePicker generates a default input id
|
|
5
5
|
require "cgi" # DataTable sort/pagination build query strings standalone
|
|
6
|
+
require "date" # Phlex 2.4's attribute type-dispatch references Date on every render
|
|
6
7
|
# phlex-rails references ActiveSupport::SafeBuffer at require time; in a Rails
|
|
7
8
|
# app it's already loaded, but a bare `require "phlex_kit"` (script/console)
|
|
8
9
|
# crashes with "uninitialized constant Phlex::ActiveSupport" without these.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: phlex_kit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.12.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matt Kennedy
|
|
@@ -306,6 +306,7 @@ files:
|
|
|
306
306
|
- app/components/phlex_kit/data_table/data_table_toolbar.rb
|
|
307
307
|
- app/components/phlex_kit/date_picker/date_picker.css
|
|
308
308
|
- app/components/phlex_kit/date_picker/date_picker.rb
|
|
309
|
+
- app/components/phlex_kit/date_picker/date_picker_controller.js
|
|
309
310
|
- app/components/phlex_kit/dialog/dialog.css
|
|
310
311
|
- app/components/phlex_kit/dialog/dialog.rb
|
|
311
312
|
- app/components/phlex_kit/dialog/dialog_close.rb
|