lostcoords-ui 0.5.0 → 0.7.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/README.md +111 -49
- data/app/assets/tailwind/lostcoords/ui/card.css +5 -2
- data/app/assets/tailwind/lostcoords/ui/{disclosure.css → collapsible.css} +1 -1
- data/app/assets/tailwind/lostcoords/ui/components/code-block.css +5 -0
- data/app/assets/tailwind/lostcoords/ui/components/collapsible.css +5 -0
- data/app/assets/tailwind/lostcoords/ui/components/dialog.css +9 -0
- data/app/assets/tailwind/lostcoords/ui/components/emoji-picker.css +5 -0
- data/app/assets/tailwind/lostcoords/ui/components/menu.css +5 -0
- data/app/assets/tailwind/lostcoords/ui/components/prose.css +3 -0
- data/app/assets/tailwind/lostcoords/ui/components/table.css +3 -0
- data/app/assets/tailwind/lostcoords/ui/components/toast.css +5 -0
- data/app/assets/tailwind/lostcoords/ui/components/tooltip.css +4 -0
- data/app/assets/tailwind/lostcoords/ui/components.css +12 -25
- data/app/assets/tailwind/lostcoords/ui/core.css +21 -0
- data/app/assets/tailwind/lostcoords/ui/emoji-picker.css +45 -47
- data/app/assets/tailwind/lostcoords/ui/popover.css +0 -52
- data/app/assets/tailwind/lostcoords/ui/{reading.css → prose.css} +6 -0
- data/app/assets/tailwind/lostcoords/ui/sheet.css +3 -64
- data/app/assets/tailwind/lostcoords/ui/theme.css +16 -1
- data/app/assets/tailwind/lostcoords/ui/toast.css +23 -0
- data/app/assets/tailwind/lostcoords/ui/tooltip.css +12 -11
- data/app/assets/tailwind/lostcoords/ui/typography.css +1 -7
- data/app/helpers/lostcoords/ui/badge_helper.rb +2 -2
- data/app/helpers/lostcoords/ui/button_helper.rb +12 -6
- data/app/helpers/lostcoords/ui/choice_helper.rb +11 -7
- data/app/helpers/lostcoords/ui/collapsible_helper.rb +9 -0
- data/app/helpers/lostcoords/ui/dialog_helper.rb +10 -5
- data/app/helpers/lostcoords/ui/emoji_picker_helper.rb +6 -0
- data/app/helpers/lostcoords/ui/feedback_helper.rb +2 -2
- data/app/helpers/lostcoords/ui/form_helper.rb +4 -3
- data/app/helpers/lostcoords/ui/glass_helper.rb +1 -1
- data/app/helpers/lostcoords/ui/menu_helper.rb +37 -2
- data/app/helpers/lostcoords/ui/navigation_helper.rb +17 -4
- data/app/helpers/lostcoords/ui/render_attributes_helper.rb +17 -1
- data/app/helpers/lostcoords/ui/sheet_helper.rb +4 -0
- data/app/helpers/lostcoords/ui/structures_helper.rb +7 -95
- data/app/helpers/lostcoords/ui/toast_helper.rb +22 -0
- data/app/helpers/lostcoords/ui/{overlay_helper.rb → tooltip_helper.rb} +3 -3
- data/app/helpers/lostcoords/ui/typography_helper.rb +30 -0
- data/app/javascript/lostcoords/ui/controllers/lc_collapsible_controller.js +1 -1
- data/app/javascript/lostcoords/ui/controllers/lc_emoji_picker_controller.js +34 -6
- data/app/javascript/lostcoords/ui/controllers/lc_kbd_controller.js +12 -0
- data/app/javascript/lostcoords/ui/controllers/lc_menu_controller.js +23 -1
- data/app/javascript/lostcoords/ui/controllers/lc_selection_controller.js +8 -16
- data/app/javascript/lostcoords/ui/controllers/lc_sheet_controller.js +15 -3
- data/app/javascript/lostcoords/ui/controllers/lc_shortcut_controller.js +45 -0
- data/app/javascript/lostcoords/ui/controllers/lc_tabs_controller.js +18 -15
- data/app/javascript/lostcoords/ui/controllers/lc_toast_region_controller.js +62 -0
- data/app/javascript/lostcoords/ui/controllers/lc_tooltip_controller.js +46 -6
- data/app/javascript/lostcoords/ui/helpers/catalog_picker.js +72 -20
- data/app/javascript/lostcoords/ui/helpers/dismiss_stack.js +23 -0
- data/app/javascript/lostcoords/ui/helpers/floating_panel.js +6 -7
- data/app/javascript/lostcoords/ui/helpers/menu_keys.js +19 -18
- data/app/javascript/lostcoords/ui/helpers/roving_focus.js +175 -0
- data/app/javascript/lostcoords/ui/helpers/shortcuts.js +162 -0
- data/app/javascript/lostcoords/ui/helpers/top_layer.js +48 -10
- data/app/javascript/lostcoords/ui/index.js +6 -0
- data/app/views/lostcoords/ui/components/_emoji_picker.html.erb +27 -27
- data/app/views/lostcoords/ui/components/_emoji_picker_grid.html.erb +3 -3
- data/app/views/lostcoords/ui/components/_lc_code_block.html.erb +1 -1
- data/lib/lostcoords/ui/action_view.rb +1 -0
- data/lib/lostcoords/ui/builders.rb +2 -2
- data/lib/lostcoords/ui/form_builder.rb +55 -10
- data/lib/lostcoords/ui/stylesheets.rb +25 -0
- data/lib/lostcoords/ui/version.rb +1 -1
- data/lib/tasks/lostcoords_ui.rake +11 -0
- metadata +23 -6
- data/config/helper_renames.json +0 -111
- data/script/migrate_helpers.rb +0 -136
|
@@ -10,8 +10,8 @@ module Lostcoords::Ui
|
|
|
10
10
|
|
|
11
11
|
def component?
|
|
12
12
|
!name.to_s.end_with?("_class") &&
|
|
13
|
-
!%i[lc_tw lc_sheet_data lc_alert_icon].include?(name) &&
|
|
14
|
-
helper != "EmojiPickerHelper"
|
|
13
|
+
!%i[lc_tw lc_sheet_data lc_shortcut_data lc_alert_icon].include?(name) &&
|
|
14
|
+
(helper != "EmojiPickerHelper" || name == :lc_emoji_picker)
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
module Lostcoords::Ui
|
|
2
|
+
# Rails wraps a field with errors in <div class="field_with_errors">. Controls this builder renders show
|
|
3
|
+
# errors themselves, so the wrapper is skipped while it renders; other forms keep Rails' behaviour.
|
|
4
|
+
module SkipsFieldErrorWrapper
|
|
5
|
+
def error_wrapping(html_tag)
|
|
6
|
+
@template_object.instance_variable_get(:@lc_skip_field_error_wrapper) ? html_tag : super
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
ActionView::Helpers::Tags::Base.prepend(SkipsFieldErrorWrapper)
|
|
10
|
+
|
|
2
11
|
# Rails form builder that renders the library's controls and connects model errors to them.
|
|
3
12
|
#
|
|
4
13
|
# <%= lc_form_with model: @project do |form| %>
|
|
@@ -16,6 +25,21 @@ module Lostcoords::Ui
|
|
|
16
25
|
date_field time_field datetime_field datetime_local_field month_field week_field
|
|
17
26
|
].freeze
|
|
18
27
|
|
|
28
|
+
# Every helper that renders a control, wrapped so Rails' error wrapper stays out of its markup.
|
|
29
|
+
WRAPPED = [ *field_helpers, :select, :collection_select, :grouped_collection_select, :time_zone_select,
|
|
30
|
+
:collection_check_boxes, :collection_radio_buttons, :switch, :choice ].uniq - %i[label fields_for fields hidden_field]
|
|
31
|
+
|
|
32
|
+
module WithoutFieldErrorWrapper
|
|
33
|
+
WRAPPED.each do |helper|
|
|
34
|
+
module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
35
|
+
def #{helper}(...)
|
|
36
|
+
without_field_error_wrapper { super(...) }
|
|
37
|
+
end
|
|
38
|
+
RUBY
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
prepend WithoutFieldErrorWrapper
|
|
42
|
+
|
|
19
43
|
INPUTS.each do |selector|
|
|
20
44
|
define_method(selector) do |method, options = {}|
|
|
21
45
|
size = control_size!(options)
|
|
@@ -33,6 +57,11 @@ module Lostcoords::Ui
|
|
|
33
57
|
super(method, choices, options, control_options(method, html_options, "select", @template.lc_select_class(size: size)), &block)
|
|
34
58
|
end
|
|
35
59
|
|
|
60
|
+
SELECT_OPTIONS = %i[include_blank prompt selected disabled].freeze
|
|
61
|
+
|
|
62
|
+
alias_method :rails_check_box, :check_box
|
|
63
|
+
private :rails_check_box
|
|
64
|
+
|
|
36
65
|
def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
|
|
37
66
|
super(method, control_options(method, options, "checkbox-input", @template.lc_checkbox_class), checked_value, unchecked_value)
|
|
38
67
|
end
|
|
@@ -44,13 +73,14 @@ module Lostcoords::Ui
|
|
|
44
73
|
|
|
45
74
|
# A checkbox drawn as a switch, with its label beside it.
|
|
46
75
|
def switch(method, label: nil, hint: nil, checked_value: "1", unchecked_value: "0", **options)
|
|
47
|
-
input =
|
|
76
|
+
input = rails_check_box(method, control_options(method, { role: "switch" }.merge(options), "switch-input", @template.lc_switch_class, described: true), checked_value, unchecked_value)
|
|
48
77
|
choice_label(method, label, hint, "switch", input)
|
|
49
78
|
end
|
|
50
79
|
|
|
51
80
|
# A checkbox with its label beside it.
|
|
52
81
|
def choice(method, label: nil, hint: nil, checked_value: "1", unchecked_value: "0", **options)
|
|
53
|
-
|
|
82
|
+
input = rails_check_box(method, control_options(method, options, "checkbox-input", @template.lc_checkbox_class, described: true), checked_value, unchecked_value)
|
|
83
|
+
choice_label(method, label, hint, "checkbox", input)
|
|
54
84
|
end
|
|
55
85
|
|
|
56
86
|
def label(method, text = nil, options = {}, &block)
|
|
@@ -68,36 +98,51 @@ module Lostcoords::Ui
|
|
|
68
98
|
end
|
|
69
99
|
variant = options.delete(:variant) || :primary
|
|
70
100
|
size = options.delete(:size) || :md
|
|
71
|
-
|
|
101
|
+
data = { slot: "button", variant: variant, size: size }.merge(options.delete(:data) || {})
|
|
102
|
+
super(value, options.merge(class: @template.lc_button_class(variant: variant, size: size, extra: options[:class]), data: data))
|
|
72
103
|
end
|
|
73
104
|
|
|
74
105
|
# Label, control, hint and the attribute's errors in one field. `as:` names the control helper;
|
|
75
|
-
#
|
|
76
|
-
|
|
106
|
+
# `as: :select` takes `choices:` and Rails' select options such as `include_blank:`. A block renders
|
|
107
|
+
# a custom control and receives its attributes to splat with `**control`.
|
|
108
|
+
def field(method, label: nil, hint: nil, as: :text_field, choices: nil, **options, &block)
|
|
77
109
|
@template.lc_field(label: label || human_name(method), id: field_id(method), hint: hint, error: errors_for(method)) do |control|
|
|
78
|
-
if block
|
|
79
|
-
|
|
110
|
+
next @template.capture(control, &block) if block
|
|
111
|
+
|
|
112
|
+
attributes = @template.send(:lc_attributes, options.except(*SELECT_OPTIONS), control.to_hash.except(:id))
|
|
113
|
+
if as.to_sym == :select
|
|
114
|
+
select(method, choices, options.slice(*SELECT_OPTIONS), attributes)
|
|
80
115
|
else
|
|
81
|
-
public_send(as, method,
|
|
116
|
+
public_send(as, method, attributes.merge(options.slice(*SELECT_OPTIONS)))
|
|
82
117
|
end
|
|
83
118
|
end
|
|
84
119
|
end
|
|
85
120
|
|
|
86
121
|
private
|
|
122
|
+
def without_field_error_wrapper
|
|
123
|
+
previous = @template.instance_variable_get(:@lc_skip_field_error_wrapper)
|
|
124
|
+
@template.instance_variable_set(:@lc_skip_field_error_wrapper, true)
|
|
125
|
+
yield
|
|
126
|
+
ensure
|
|
127
|
+
@template.instance_variable_set(:@lc_skip_field_error_wrapper, previous)
|
|
128
|
+
end
|
|
129
|
+
|
|
87
130
|
def control_size!(options)
|
|
88
131
|
options[:size].is_a?(Symbol) || options[:size].is_a?(String) && options[:size].match?(/\A[a-z]+\z/) ? options.delete(:size).to_sym : :md
|
|
89
132
|
end
|
|
90
133
|
|
|
91
|
-
|
|
134
|
+
# described: points aria-describedby at the error a choice label renders, as lc_field does for its control.
|
|
135
|
+
def control_options(method, options, slot, classes, described: false)
|
|
92
136
|
options = options.dup
|
|
93
137
|
aria = (options.delete(:aria) || {}).dup
|
|
94
138
|
aria[:invalid] = true if errors_for(method).any? && !aria.key?(:invalid)
|
|
139
|
+
aria[:describedby] = [ aria[:describedby], "#{field_id(method)}-error" ].compact.join(" ") if described && errors_for(method).any?
|
|
95
140
|
data = { slot: slot }.merge(options.delete(:data) || {})
|
|
96
141
|
options.merge(class: @template.lc_tw(classes, options[:class]), aria: aria, data: data)
|
|
97
142
|
end
|
|
98
143
|
|
|
99
144
|
def choice_label(method, text, hint, slot, input)
|
|
100
|
-
@template.send(:lc_choice_label, slot, text || human_name(method), hint, input, for: field_id(method))
|
|
145
|
+
@template.send(:lc_choice_label, slot, text || human_name(method), hint, input, errors: errors_for(method), error_id: "#{field_id(method)}-error", for: field_id(method))
|
|
101
146
|
end
|
|
102
147
|
|
|
103
148
|
def errors_for(method)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require "fileutils"
|
|
2
|
+
require "pathname"
|
|
3
|
+
|
|
4
|
+
module Lostcoords::Ui
|
|
5
|
+
# The Tailwind entries a host can import: the document defaults, core.css and one file per opt-in component.
|
|
6
|
+
module Stylesheets
|
|
7
|
+
ROOT = Pathname(File.expand_path("../../../app/assets/tailwind/lostcoords/ui", __dir__))
|
|
8
|
+
|
|
9
|
+
def self.entries
|
|
10
|
+
[ ROOT.join("base.css"), ROOT.join("core.css"), *ROOT.glob("components/*.css").sort ]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# tailwindcss-rails gives an engine one generated import, of engine.css. These proxies give every
|
|
14
|
+
# entry a stable path in the host, such as builds/tailwind/lostcoords_ui/components/dialog.css.
|
|
15
|
+
def self.write(builds)
|
|
16
|
+
directory = Pathname(builds).join("lostcoords_ui")
|
|
17
|
+
FileUtils.rm_rf(directory)
|
|
18
|
+
entries.each do |entry|
|
|
19
|
+
path = directory.join(entry.relative_path_from(ROOT))
|
|
20
|
+
FileUtils.mkdir_p(path.dirname)
|
|
21
|
+
path.write("/* Generated by lostcoords-ui before every Tailwind build; do not edit. */\n@import \"#{entry}\";\n")
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -13,3 +13,14 @@ namespace :lostcoords do
|
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
|
+
|
|
17
|
+
# Runs with tailwindcss-rails' own engines step, before every tailwindcss:build and tailwindcss:watch.
|
|
18
|
+
# Apps without tailwindcss-rails import the gem's stylesheets by path instead.
|
|
19
|
+
if defined?(Tailwindcss::Engines)
|
|
20
|
+
namespace :tailwindcss do
|
|
21
|
+
task :engines do
|
|
22
|
+
require "lostcoords/ui/stylesheets"
|
|
23
|
+
Lostcoords::Ui::Stylesheets.write(Rails.root.join("app/assets/builds/tailwind"))
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lostcoords-ui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lost Coordinates
|
|
@@ -90,20 +90,31 @@ files:
|
|
|
90
90
|
- app/assets/tailwind/lostcoords/ui/card.css
|
|
91
91
|
- app/assets/tailwind/lostcoords/ui/choice.css
|
|
92
92
|
- app/assets/tailwind/lostcoords/ui/code-block.css
|
|
93
|
+
- app/assets/tailwind/lostcoords/ui/collapsible.css
|
|
93
94
|
- app/assets/tailwind/lostcoords/ui/components.css
|
|
95
|
+
- app/assets/tailwind/lostcoords/ui/components/code-block.css
|
|
96
|
+
- app/assets/tailwind/lostcoords/ui/components/collapsible.css
|
|
97
|
+
- app/assets/tailwind/lostcoords/ui/components/dialog.css
|
|
98
|
+
- app/assets/tailwind/lostcoords/ui/components/emoji-picker.css
|
|
99
|
+
- app/assets/tailwind/lostcoords/ui/components/menu.css
|
|
100
|
+
- app/assets/tailwind/lostcoords/ui/components/prose.css
|
|
101
|
+
- app/assets/tailwind/lostcoords/ui/components/table.css
|
|
102
|
+
- app/assets/tailwind/lostcoords/ui/components/toast.css
|
|
103
|
+
- app/assets/tailwind/lostcoords/ui/components/tooltip.css
|
|
94
104
|
- app/assets/tailwind/lostcoords/ui/copy-button.css
|
|
105
|
+
- app/assets/tailwind/lostcoords/ui/core.css
|
|
95
106
|
- app/assets/tailwind/lostcoords/ui/dialog.css
|
|
96
|
-
- app/assets/tailwind/lostcoords/ui/disclosure.css
|
|
97
107
|
- app/assets/tailwind/lostcoords/ui/emoji-picker.css
|
|
98
108
|
- app/assets/tailwind/lostcoords/ui/field.css
|
|
99
109
|
- app/assets/tailwind/lostcoords/ui/glass.css
|
|
100
110
|
- app/assets/tailwind/lostcoords/ui/layout.css
|
|
101
111
|
- app/assets/tailwind/lostcoords/ui/popover.css
|
|
102
|
-
- app/assets/tailwind/lostcoords/ui/
|
|
112
|
+
- app/assets/tailwind/lostcoords/ui/prose.css
|
|
103
113
|
- app/assets/tailwind/lostcoords/ui/sheet.css
|
|
104
114
|
- app/assets/tailwind/lostcoords/ui/squircle.css
|
|
105
115
|
- app/assets/tailwind/lostcoords/ui/table.css
|
|
106
116
|
- app/assets/tailwind/lostcoords/ui/theme.css
|
|
117
|
+
- app/assets/tailwind/lostcoords/ui/toast.css
|
|
107
118
|
- app/assets/tailwind/lostcoords/ui/tooltip.css
|
|
108
119
|
- app/assets/tailwind/lostcoords/ui/typography.css
|
|
109
120
|
- app/assets/tailwind/lostcoords/ui/ui.css
|
|
@@ -114,6 +125,7 @@ files:
|
|
|
114
125
|
- app/helpers/lostcoords/ui/card_helper.rb
|
|
115
126
|
- app/helpers/lostcoords/ui/choice_helper.rb
|
|
116
127
|
- app/helpers/lostcoords/ui/code_block_helper.rb
|
|
128
|
+
- app/helpers/lostcoords/ui/collapsible_helper.rb
|
|
117
129
|
- app/helpers/lostcoords/ui/copy_button_helper.rb
|
|
118
130
|
- app/helpers/lostcoords/ui/description_list_helper.rb
|
|
119
131
|
- app/helpers/lostcoords/ui/dialog_helper.rb
|
|
@@ -125,7 +137,6 @@ files:
|
|
|
125
137
|
- app/helpers/lostcoords/ui/layout_helper.rb
|
|
126
138
|
- app/helpers/lostcoords/ui/menu_helper.rb
|
|
127
139
|
- app/helpers/lostcoords/ui/navigation_helper.rb
|
|
128
|
-
- app/helpers/lostcoords/ui/overlay_helper.rb
|
|
129
140
|
- app/helpers/lostcoords/ui/primitives_helper.rb
|
|
130
141
|
- app/helpers/lostcoords/ui/reading_helper.rb
|
|
131
142
|
- app/helpers/lostcoords/ui/render_attributes_helper.rb
|
|
@@ -133,6 +144,8 @@ files:
|
|
|
133
144
|
- app/helpers/lostcoords/ui/structures_helper.rb
|
|
134
145
|
- app/helpers/lostcoords/ui/table_helper.rb
|
|
135
146
|
- app/helpers/lostcoords/ui/tailwind_helper.rb
|
|
147
|
+
- app/helpers/lostcoords/ui/toast_helper.rb
|
|
148
|
+
- app/helpers/lostcoords/ui/tooltip_helper.rb
|
|
136
149
|
- app/helpers/lostcoords/ui/translation_helper.rb
|
|
137
150
|
- app/helpers/lostcoords/ui/typography_helper.rb
|
|
138
151
|
- app/javascript/lostcoords/ui/controllers/lc_code_block_controller.js
|
|
@@ -141,12 +154,15 @@ files:
|
|
|
141
154
|
- app/javascript/lostcoords/ui/controllers/lc_copy_controller.js
|
|
142
155
|
- app/javascript/lostcoords/ui/controllers/lc_dialog_controller.js
|
|
143
156
|
- app/javascript/lostcoords/ui/controllers/lc_emoji_picker_controller.js
|
|
157
|
+
- app/javascript/lostcoords/ui/controllers/lc_kbd_controller.js
|
|
144
158
|
- app/javascript/lostcoords/ui/controllers/lc_menu_controller.js
|
|
145
159
|
- app/javascript/lostcoords/ui/controllers/lc_popover_controller.js
|
|
146
160
|
- app/javascript/lostcoords/ui/controllers/lc_selection_controller.js
|
|
147
161
|
- app/javascript/lostcoords/ui/controllers/lc_sheet_controller.js
|
|
162
|
+
- app/javascript/lostcoords/ui/controllers/lc_shortcut_controller.js
|
|
148
163
|
- app/javascript/lostcoords/ui/controllers/lc_tabs_controller.js
|
|
149
164
|
- app/javascript/lostcoords/ui/controllers/lc_toast_controller.js
|
|
165
|
+
- app/javascript/lostcoords/ui/controllers/lc_toast_region_controller.js
|
|
150
166
|
- app/javascript/lostcoords/ui/controllers/lc_toggle_controller.js
|
|
151
167
|
- app/javascript/lostcoords/ui/controllers/lc_tooltip_controller.js
|
|
152
168
|
- app/javascript/lostcoords/ui/helpers/catalog_picker.js
|
|
@@ -155,7 +171,9 @@ files:
|
|
|
155
171
|
- app/javascript/lostcoords/ui/helpers/dismiss_stack.js
|
|
156
172
|
- app/javascript/lostcoords/ui/helpers/floating_panel.js
|
|
157
173
|
- app/javascript/lostcoords/ui/helpers/menu_keys.js
|
|
174
|
+
- app/javascript/lostcoords/ui/helpers/roving_focus.js
|
|
158
175
|
- app/javascript/lostcoords/ui/helpers/sheet_motion.js
|
|
176
|
+
- app/javascript/lostcoords/ui/helpers/shortcuts.js
|
|
159
177
|
- app/javascript/lostcoords/ui/helpers/top_layer.js
|
|
160
178
|
- app/javascript/lostcoords/ui/helpers/viewport.js
|
|
161
179
|
- app/javascript/lostcoords/ui/index.js
|
|
@@ -168,7 +186,6 @@ files:
|
|
|
168
186
|
- config/emoji_search_aliases.yml
|
|
169
187
|
- config/emoji_search_names.yml
|
|
170
188
|
- config/emoji_search_names_ja.yml
|
|
171
|
-
- config/helper_renames.json
|
|
172
189
|
- config/importmap.rb
|
|
173
190
|
- config/locales/en.yml
|
|
174
191
|
- config/locales/es.yml
|
|
@@ -184,10 +201,10 @@ files:
|
|
|
184
201
|
- lib/lostcoords/ui/parts.rb
|
|
185
202
|
- lib/lostcoords/ui/rails.rb
|
|
186
203
|
- lib/lostcoords/ui/resources.rb
|
|
204
|
+
- lib/lostcoords/ui/stylesheets.rb
|
|
187
205
|
- lib/lostcoords/ui/tokens.rb
|
|
188
206
|
- lib/lostcoords/ui/version.rb
|
|
189
207
|
- lib/tasks/lostcoords_ui.rake
|
|
190
|
-
- script/migrate_helpers.rb
|
|
191
208
|
- vendor/heroicons/LICENSE
|
|
192
209
|
- vendor/heroicons/icons.json
|
|
193
210
|
homepage: https://github.com/lostcoords/ui
|
data/config/helper_renames.json
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"avatar_class": "lc_avatar_class",
|
|
3
|
-
"avatar_stack_class": "lc_avatar_stack_class",
|
|
4
|
-
"avatar_stack_row_class": "lc_avatar_stack_row_class",
|
|
5
|
-
"badge_class": "lc_badge_class",
|
|
6
|
-
"button_class": "lc_button_class",
|
|
7
|
-
"button_variants": "lc_button_variants",
|
|
8
|
-
"card_class": "lc_card_class",
|
|
9
|
-
"card_surface_class": "lc_card_class",
|
|
10
|
-
"container_class": "lc_container_class",
|
|
11
|
-
"dialog_class": "lc_dialog_class",
|
|
12
|
-
"dialog_kinds": "lc_dialog_kinds",
|
|
13
|
-
"dialog_surface_class": "lc_dialog_surface_class",
|
|
14
|
-
"dropdown_trigger_class": "lc_dropdown_trigger_class",
|
|
15
|
-
"emoji_picker_count": "lc_emoji_picker_count",
|
|
16
|
-
"emoji_picker_groups": "lc_emoji_picker_groups",
|
|
17
|
-
"emoji_picker_search_labels": "lc_emoji_picker_search_labels",
|
|
18
|
-
"emoji_picker_search_name": "lc_emoji_picker_search_name",
|
|
19
|
-
"emoji_picker_search_text": "lc_emoji_picker_search_text",
|
|
20
|
-
"emoji_picker_toneable?": "lc_emoji_picker_toneable?",
|
|
21
|
-
"emoji_picker_version": "lc_emoji_picker_version",
|
|
22
|
-
"empty_state_class": "lc_empty_state_class",
|
|
23
|
-
"field_class": "lc_field_class",
|
|
24
|
-
"field_label_class": "lc_field_label_class",
|
|
25
|
-
"form_actions_class": "lc_inline_class",
|
|
26
|
-
"form_alert_class": "lc_alert_class",
|
|
27
|
-
"form_alert_icon": "lc_alert_icon",
|
|
28
|
-
"form_card_class": "lc_card_class",
|
|
29
|
-
"glass_class": "lc_glass_class",
|
|
30
|
-
"heading_class": "lc_heading_class",
|
|
31
|
-
"heroicon": "lc_icon",
|
|
32
|
-
"icon_badge_class": "lc_icon_badge_class",
|
|
33
|
-
"icon_button_class": "lc_icon_button_class",
|
|
34
|
-
"icon_medallion_class": "lc_icon_badge_class",
|
|
35
|
-
"inline_class": "lc_inline_class",
|
|
36
|
-
"input_class": "lc_input_class",
|
|
37
|
-
"menu_option_class": "lc_menu_option_class",
|
|
38
|
-
"menu_popover_class": "lc_menu_popover_class",
|
|
39
|
-
"pill_class": "lc_toggle_class",
|
|
40
|
-
"pill_row_class": "lc_inline_class",
|
|
41
|
-
"popover_class": "lc_popover_class",
|
|
42
|
-
"prose_class": "lc_prose_class",
|
|
43
|
-
"section_header_class": "lc_section_header_class",
|
|
44
|
-
"segmented_class": "lc_toggle_group_class",
|
|
45
|
-
"segmented_tab_class": "lc_toggle_group_item_class",
|
|
46
|
-
"select_class": "lc_select_class",
|
|
47
|
-
"sheet_chip_class": "lc_sheet_chip_class",
|
|
48
|
-
"sheet_data": "lc_sheet_data",
|
|
49
|
-
"sheet_datetime_input_class": "lc_sheet_datetime_input_class",
|
|
50
|
-
"sheet_row_class": "lc_sheet_row_class",
|
|
51
|
-
"sheet_row_label_class": "lc_sheet_row_label_class",
|
|
52
|
-
"sheet_text_input_class": "lc_sheet_text_input_class",
|
|
53
|
-
"skeleton_class": "lc_skeleton_class",
|
|
54
|
-
"spinner_class": "lc_spinner_class",
|
|
55
|
-
"stack_class": "lc_stack_class",
|
|
56
|
-
"status_pill_class": "lc_badge_class",
|
|
57
|
-
"text_class": "lc_text_class",
|
|
58
|
-
"textarea_class": "lc_textarea_class",
|
|
59
|
-
"tw": "lc_tw",
|
|
60
|
-
"ui_attributes": "lc_attributes",
|
|
61
|
-
"ui_avatar": "lc_avatar",
|
|
62
|
-
"ui_avatar_stack": "lc_avatar_stack",
|
|
63
|
-
"ui_badge": "lc_badge",
|
|
64
|
-
"ui_button": "lc_button",
|
|
65
|
-
"ui_button_attributes": "lc_button_attributes",
|
|
66
|
-
"ui_button_content": "lc_button_content",
|
|
67
|
-
"ui_button_link_to": "lc_button_link_to",
|
|
68
|
-
"ui_button_to": "lc_button_to",
|
|
69
|
-
"ui_card": "lc_card",
|
|
70
|
-
"ui_card_surface": "lc_card",
|
|
71
|
-
"ui_container": "lc_container",
|
|
72
|
-
"ui_copy_button": "lc_copy_button",
|
|
73
|
-
"ui_copy_content": "lc_copy_content",
|
|
74
|
-
"ui_dialog": "lc_dialog",
|
|
75
|
-
"ui_disclosure": "lc_collapsible",
|
|
76
|
-
"ui_emoji_picker": "lc_emoji_picker",
|
|
77
|
-
"ui_empty_state": "lc_empty_state",
|
|
78
|
-
"ui_field": "lc_field",
|
|
79
|
-
"ui_form_actions": "lc_inline",
|
|
80
|
-
"ui_form_alert": "lc_alert",
|
|
81
|
-
"ui_form_card": "lc_card",
|
|
82
|
-
"ui_heading": "lc_heading",
|
|
83
|
-
"ui_icon_badge": "lc_icon_badge",
|
|
84
|
-
"ui_icon_button": "lc_icon_button",
|
|
85
|
-
"ui_inline": "lc_inline",
|
|
86
|
-
"ui_input": "lc_input",
|
|
87
|
-
"ui_label!": "lc_label!",
|
|
88
|
-
"ui_medallion": "lc_icon_badge",
|
|
89
|
-
"ui_menu": "lc_menu",
|
|
90
|
-
"ui_menu_option": "lc_menu_option",
|
|
91
|
-
"ui_normalize_attributes": "lc_normalize_attributes",
|
|
92
|
-
"ui_option!": "lc_option!",
|
|
93
|
-
"ui_pill": "lc_toggle",
|
|
94
|
-
"ui_pill_row": "lc_inline",
|
|
95
|
-
"ui_popover": "lc_popover",
|
|
96
|
-
"ui_prose": "lc_prose",
|
|
97
|
-
"ui_render_dialog": "lc_render_dialog",
|
|
98
|
-
"ui_render_panel": "lc_render_panel",
|
|
99
|
-
"ui_section": "lc_section",
|
|
100
|
-
"ui_segmented": "lc_toggle_group",
|
|
101
|
-
"ui_segmented_tab": "lc_toggle_group_item",
|
|
102
|
-
"ui_select": "lc_select",
|
|
103
|
-
"ui_sheet": "lc_dialog",
|
|
104
|
-
"ui_skeleton": "lc_skeleton",
|
|
105
|
-
"ui_spinner": "lc_spinner",
|
|
106
|
-
"ui_stack": "lc_stack",
|
|
107
|
-
"ui_status_pill": "lc_badge",
|
|
108
|
-
"ui_text": "lc_text",
|
|
109
|
-
"ui_textarea": "lc_textarea",
|
|
110
|
-
"ui_toast": "lc_toast"
|
|
111
|
-
}
|
data/script/migrate_helpers.rb
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
require "json"
|
|
4
|
-
require "find"
|
|
5
|
-
require "optparse"
|
|
6
|
-
require "ripper"
|
|
7
|
-
|
|
8
|
-
module HelperMigration
|
|
9
|
-
LIBRARY = File.expand_path("..", __dir__)
|
|
10
|
-
NAMES = JSON.parse(File.read(File.join(LIBRARY, "config/helper_renames.json"))).freeze
|
|
11
|
-
PARTIALS = %w[dialog disclosure].to_h do |name|
|
|
12
|
-
[ "lostcoords/ui/components/ui_#{name}", "lostcoords/ui/components/lc_#{name}" ]
|
|
13
|
-
end.freeze
|
|
14
|
-
|
|
15
|
-
def self.method_locations(node, locations = {})
|
|
16
|
-
return locations unless node.is_a?(Array)
|
|
17
|
-
|
|
18
|
-
name = case node.first
|
|
19
|
-
when :def, :vcall, :fcall, :command, :symbol then node[1]
|
|
20
|
-
when :defs, :call, :command_call then node[3]
|
|
21
|
-
end
|
|
22
|
-
locations[name[2]] = true if name.is_a?(Array) && name.first == :@ident
|
|
23
|
-
node.each { |child| method_locations(child, locations) }
|
|
24
|
-
locations
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def self.rewrite(source, program: source, prefix_lines: 0)
|
|
28
|
-
syntax = Ripper.sexp(program)
|
|
29
|
-
raise ArgumentError, "Cannot parse Ruby source for helper migration" unless syntax
|
|
30
|
-
|
|
31
|
-
methods = method_locations(syntax)
|
|
32
|
-
offsets = [ 0 ]
|
|
33
|
-
source.each_line { |line| offsets << offsets.last + line.bytesize }
|
|
34
|
-
contexts = []
|
|
35
|
-
edits = Ripper.lex(program).filter_map do |position, type, value, _|
|
|
36
|
-
replacement = case type
|
|
37
|
-
when :on_ident then NAMES[value] if methods[position]
|
|
38
|
-
when :on_tstring_content then contexts.last == :symbol ? NAMES[value] : PARTIALS[value]
|
|
39
|
-
end
|
|
40
|
-
case type
|
|
41
|
-
when :on_symbeg then contexts << :symbol unless value == ":"
|
|
42
|
-
when :on_qsymbols_beg, :on_symbols_beg then contexts << :symbol
|
|
43
|
-
when :on_tstring_beg, :on_heredoc_beg, :on_qwords_beg, :on_words_beg, :on_regexp_beg then contexts << :string
|
|
44
|
-
when :on_tstring_end, :on_heredoc_end, :on_regexp_end then contexts.pop
|
|
45
|
-
end
|
|
46
|
-
line = position[0] - prefix_lines
|
|
47
|
-
[ offsets.fetch(line - 1) + position[1], value.bytesize, replacement ] if replacement && line.positive?
|
|
48
|
-
end
|
|
49
|
-
updated = source.b
|
|
50
|
-
edits.reverse_each { |offset, length, value| updated[offset, length] = value.b }
|
|
51
|
-
updated.force_encoding(source.encoding)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def self.ruby(source)
|
|
55
|
-
rewrite(source)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def self.erb(source)
|
|
59
|
-
program = source.b.gsub(/[^\r\n]/n, " ")
|
|
60
|
-
source.to_enum(:scan, /(<%(?!%)(?:==?|-)?)(.*?)(-?%>)/m).each do
|
|
61
|
-
match = Regexp.last_match
|
|
62
|
-
opening, body, closing = match.captures
|
|
63
|
-
next if body.start_with?("#")
|
|
64
|
-
|
|
65
|
-
start = match.pre_match.bytesize + opening.bytesize
|
|
66
|
-
program[start, body.bytesize] = body.b
|
|
67
|
-
program[start + body.bytesize, closing.bytesize] = ";" + " " * (closing.bytesize - 1)
|
|
68
|
-
end
|
|
69
|
-
signature = source[/<%#\s*locals:\s*\((.*?)\)\s*%>/m, 1]
|
|
70
|
-
prefix = "def __template(#{signature})\n"
|
|
71
|
-
suffix = "\nend"
|
|
72
|
-
rewrite(source, program: prefix + program.force_encoding(source.encoding) + suffix, prefix_lines: prefix.count("\n"))
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def self.markdown(source)
|
|
76
|
-
source = source.gsub(/(^```(ruby|rb|erb)[^\n]*\n)(.*?)(^```[ \t]*$)/m) do
|
|
77
|
-
opening, language, body, closing = Regexp.last_match.captures
|
|
78
|
-
"#{opening}#{language == 'erb' ? erb(body) : ruby(body)}#{closing}"
|
|
79
|
-
end
|
|
80
|
-
source.gsub(/`([^`\n]+)`/) { |match| NAMES.key?(Regexp.last_match[1]) ? "`#{NAMES.fetch(Regexp.last_match[1])}`" : match }
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def self.changes(root)
|
|
84
|
-
files = Find.find(root).filter_map do |path|
|
|
85
|
-
next if File.symlink?(path)
|
|
86
|
-
if File.directory?(path)
|
|
87
|
-
name = File.basename(path)
|
|
88
|
-
Find.prune if path != root && (name.start_with?(".") || %w[node_modules vendor tmp log storage pkg coverage builds dist].include?(name))
|
|
89
|
-
next
|
|
90
|
-
end
|
|
91
|
-
path.delete_prefix("#{root}/")
|
|
92
|
-
end
|
|
93
|
-
files.sort.filter_map do |relative|
|
|
94
|
-
path = File.join(root, relative)
|
|
95
|
-
next if File.symlink?(path) || relative.start_with?("vendor/")
|
|
96
|
-
next if root == LIBRARY && (relative == "README.md" || relative.start_with?("docs/", "plans/"))
|
|
97
|
-
|
|
98
|
-
extension = File.extname(path)
|
|
99
|
-
next unless %w[.rb .erb .md].include?(extension) || extension.empty?
|
|
100
|
-
|
|
101
|
-
source = File.binread(path).force_encoding(Encoding::UTF_8)
|
|
102
|
-
updated = case extension
|
|
103
|
-
when ".rb" then ruby(source)
|
|
104
|
-
when ".erb" then erb(source)
|
|
105
|
-
when ".md" then markdown(source)
|
|
106
|
-
else ruby(source) if source.lines.first&.match?(/\A#!.*ruby/)
|
|
107
|
-
end
|
|
108
|
-
next unless updated
|
|
109
|
-
|
|
110
|
-
name = File.basename(path).sub(/\A_ui_(dialog|disclosure)\.html\.erb\z/, '_lc_\1.html.erb')
|
|
111
|
-
destination = File.join(File.dirname(path), name)
|
|
112
|
-
abort "Refusing to overwrite #{destination}" if destination != path && (File.exist?(destination) || File.symlink?(destination))
|
|
113
|
-
[ path, destination, updated ] if updated != source || destination != path
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
if $PROGRAM_NAME == __FILE__
|
|
119
|
-
write = false
|
|
120
|
-
OptionParser.new do |options|
|
|
121
|
-
options.banner = "Usage: ruby migrate_helpers.rb [checkout] [--write]"
|
|
122
|
-
options.on("--write", "Apply the migration after checking every destination") { write = true }
|
|
123
|
-
end.parse!
|
|
124
|
-
abort "Expected one checkout path" if ARGV.size > 1
|
|
125
|
-
root = File.realpath(ARGV.first || Dir.pwd)
|
|
126
|
-
changes = HelperMigration.changes(root)
|
|
127
|
-
changes.each do |path, destination, source|
|
|
128
|
-
puts path.delete_prefix("#{root}/")
|
|
129
|
-
next unless write
|
|
130
|
-
|
|
131
|
-
File.binwrite(path, source)
|
|
132
|
-
File.rename(path, destination) unless path == destination
|
|
133
|
-
end
|
|
134
|
-
puts "#{changes.size} files #{write ? 'updated' : 'would change'}"
|
|
135
|
-
exit 1 if changes.any? && !write
|
|
136
|
-
end
|