poetry-core 0.0.2
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 +7 -0
- data/CHANGELOG.md +3 -0
- data/DESIGN.md +145 -0
- data/LICENSE.txt +21 -0
- data/README.md +30 -0
- data/THIRD_PARTY_NOTICES.md +507 -0
- data/app/components/poetry/core/box/component.rb +82 -0
- data/app/components/poetry/core/component.rb +390 -0
- data/app/components/poetry/core/concerns/agent_tools.rb +418 -0
- data/app/components/poetry/core/concerns/declared_attributes.rb +267 -0
- data/app/components/poetry/core/concerns/introspection.rb +533 -0
- data/app/components/poetry/core/concerns/options.rb +262 -0
- data/app/components/poetry/core/concerns/parts.rb +148 -0
- data/app/components/poetry/core/concerns/stimulus.rb +363 -0
- data/app/components/poetry/core/concerns/styles.rb +323 -0
- data/app/components/poetry/core/style.rb +150 -0
- data/app/components/poetry/core/wrapper/component.rb +90 -0
- data/app/javascript/poetry/core/accordion_controller.js +165 -0
- data/app/javascript/poetry/core/action_bar_controller.js +109 -0
- data/app/javascript/poetry/core/autocomplete_controller.js +220 -0
- data/app/javascript/poetry/core/calendar_controller.js +406 -0
- data/app/javascript/poetry/core/carousel_controller.js +167 -0
- data/app/javascript/poetry/core/checkbox_group_controller.js +97 -0
- data/app/javascript/poetry/core/checked_controller.js +208 -0
- data/app/javascript/poetry/core/clipboard_text_controller.js +111 -0
- data/app/javascript/poetry/core/combobox_controller.js +1095 -0
- data/app/javascript/poetry/core/command_controller.js +510 -0
- data/app/javascript/poetry/core/context_menu_controller.js +204 -0
- data/app/javascript/poetry/core/date_field_controller.js +584 -0
- data/app/javascript/poetry/core/date_picker_controller.js +111 -0
- data/app/javascript/poetry/core/deferred_controller.js +111 -0
- data/app/javascript/poetry/core/dialog_controller.js +206 -0
- data/app/javascript/poetry/core/dismissable_controller.js +182 -0
- data/app/javascript/poetry/core/drawer_controller.js +365 -0
- data/app/javascript/poetry/core/file_input_controller.js +191 -0
- data/app/javascript/poetry/core/focus_scope_controller.js +162 -0
- data/app/javascript/poetry/core/helpers/announce.js +228 -0
- data/app/javascript/poetry/core/helpers/breakpoint.js +28 -0
- data/app/javascript/poetry/core/helpers/collection.js +18 -0
- data/app/javascript/poetry/core/helpers/direction.js +15 -0
- data/app/javascript/poetry/core/helpers/escape.js +38 -0
- data/app/javascript/poetry/core/helpers/filter_rank.js +104 -0
- data/app/javascript/poetry/core/helpers/focus_guards.js +46 -0
- data/app/javascript/poetry/core/helpers/hotkey.js +43 -0
- data/app/javascript/poetry/core/helpers/id_integrity.js +65 -0
- data/app/javascript/poetry/core/helpers/incomplete_date.js +328 -0
- data/app/javascript/poetry/core/helpers/mask.js +283 -0
- data/app/javascript/poetry/core/helpers/portal.js +217 -0
- data/app/javascript/poetry/core/helpers/presence.js +210 -0
- data/app/javascript/poetry/core/helpers/registration_guard.js +76 -0
- data/app/javascript/poetry/core/helpers/scroll_lock.js +67 -0
- data/app/javascript/poetry/core/helpers/scroller_geometry.js +422 -0
- data/app/javascript/poetry/core/helpers/state.js +80 -0
- data/app/javascript/poetry/core/helpers/tabbable.js +56 -0
- data/app/javascript/poetry/core/helpers/turbo_cache.js +21 -0
- data/app/javascript/poetry/core/helpers/typeahead.js +85 -0
- data/app/javascript/poetry/core/hotkey_controller.js +55 -0
- data/app/javascript/poetry/core/hover_card_controller.js +431 -0
- data/app/javascript/poetry/core/index.js +218 -0
- data/app/javascript/poetry/core/mask_controller.js +500 -0
- data/app/javascript/poetry/core/menu_controller.js +1050 -0
- data/app/javascript/poetry/core/menubar_controller.js +329 -0
- data/app/javascript/poetry/core/message_scroller_controller.js +930 -0
- data/app/javascript/poetry/core/navigation_menu_controller.js +458 -0
- data/app/javascript/poetry/core/number_field_controller.js +404 -0
- data/app/javascript/poetry/core/optimistic_form_controller.js +56 -0
- data/app/javascript/poetry/core/otp_controller.js +219 -0
- data/app/javascript/poetry/core/popover_controller.js +300 -0
- data/app/javascript/poetry/core/popper_controller.js +439 -0
- data/app/javascript/poetry/core/pressed_controller.js +74 -0
- data/app/javascript/poetry/core/questionnaire_controller.js +468 -0
- data/app/javascript/poetry/core/radio_group_controller.js +197 -0
- data/app/javascript/poetry/core/resizable_controller.js +202 -0
- data/app/javascript/poetry/core/roving_focus_controller.js +215 -0
- data/app/javascript/poetry/core/scroll_spy_controller.js +84 -0
- data/app/javascript/poetry/core/search_field_controller.js +95 -0
- data/app/javascript/poetry/core/select_controller.js +924 -0
- data/app/javascript/poetry/core/sensitive_input_controller.js +195 -0
- data/app/javascript/poetry/core/sheet_controller.js +24 -0
- data/app/javascript/poetry/core/sidebar_controller.js +272 -0
- data/app/javascript/poetry/core/slider_controller.js +419 -0
- data/app/javascript/poetry/core/state_controller.js +82 -0
- data/app/javascript/poetry/core/table_selection_controller.js +153 -0
- data/app/javascript/poetry/core/tabs_controller.js +151 -0
- data/app/javascript/poetry/core/tag_group_controller.js +134 -0
- data/app/javascript/poetry/core/toast_controller.js +228 -0
- data/app/javascript/poetry/core/toast_trigger_controller.js +26 -0
- data/app/javascript/poetry/core/toaster_controller.js +197 -0
- data/app/javascript/poetry/core/toggle_group_controller.js +206 -0
- data/app/javascript/poetry/core/tooltip_controller.js +541 -0
- data/app/javascript/poetry/core/tree_controller.js +265 -0
- data/app/javascript/poetry/core/vendor/floating_ui_core.js +1043 -0
- data/app/javascript/poetry/core/vendor/floating_ui_dom.js +794 -0
- data/app/javascript/poetry/core/vendor/floating_ui_utils.js +141 -0
- data/app/javascript/poetry/core/vendor/floating_ui_utils_dom.js +170 -0
- data/app/views/poetry/core/preview.html.erb +13 -0
- data/config/component_registry.yml +20 -0
- data/config/controllers_manifest.json +1528 -0
- data/config/importmap.rb +11 -0
- data/config/state_vocabulary.json +31 -0
- data/lib/active_model/type/list.rb +33 -0
- data/lib/active_model/type/symbol.rb +36 -0
- data/lib/poetry/core/check/stable_identity.rb +104 -0
- data/lib/poetry/core/check.rb +1445 -0
- data/lib/poetry/core/config.rb +286 -0
- data/lib/poetry/core/contrib/wrapped_helper.rb +68 -0
- data/lib/poetry/core/css/bem_merger.rb +45 -0
- data/lib/poetry/core/css/bem_reference.rb +87 -0
- data/lib/poetry/core/css/override_scan.rb +110 -0
- data/lib/poetry/core/css/resolver.rb +161 -0
- data/lib/poetry/core/css/safelist.rb +41 -0
- data/lib/poetry/core/css/tailwind_merger.rb +102 -0
- data/lib/poetry/core/css/template_classes.rb +102 -0
- data/lib/poetry/core/css/theme_coverage.rb +72 -0
- data/lib/poetry/core/css/var_coverage.rb +75 -0
- data/lib/poetry/core/css/verifier.rb +106 -0
- data/lib/poetry/core/design_lint.rb +720 -0
- data/lib/poetry/core/design_md/import.rb +250 -0
- data/lib/poetry/core/design_md.rb +461 -0
- data/lib/poetry/core/engine.rb +71 -0
- data/lib/poetry/core/errors.rb +53 -0
- data/lib/poetry/core/html/attributes.rb +667 -0
- data/lib/poetry/core/icons.rb +157 -0
- data/lib/poetry/core/llms_text.rb +354 -0
- data/lib/poetry/core/page_architectures.rb +304 -0
- data/lib/poetry/core/part_contract.rb +285 -0
- data/lib/poetry/core/preview/abstract.rb +121 -0
- data/lib/poetry/core/preview/base.rb +227 -0
- data/lib/poetry/core/preview/sidecarable.rb +136 -0
- data/lib/poetry/core/preview/template.rb +186 -0
- data/lib/poetry/core/recipe_items.rb +82 -0
- data/lib/poetry/core/registry.rb +363 -0
- data/lib/poetry/core/registry_address.rb +115 -0
- data/lib/poetry/core/registry_client.rb +217 -0
- data/lib/poetry/core/registry_installer.rb +234 -0
- data/lib/poetry/core/registry_items.rb +184 -0
- data/lib/poetry/core/skill_text.rb +288 -0
- data/lib/poetry/core/stable_id.rb +110 -0
- data/lib/poetry/core/stimulus/builder.rb +395 -0
- data/lib/poetry/core/stimulus/declarations.rb +444 -0
- data/lib/poetry/core/stimulus/manifest.rb +68 -0
- data/lib/poetry/core/stimulus/merger.rb +131 -0
- data/lib/poetry/core/stimulus_contract.rb +263 -0
- data/lib/poetry/core/tag_helper.rb +10 -0
- data/lib/poetry/core/template_compile.rb +74 -0
- data/lib/poetry/core/token_import.rb +317 -0
- data/lib/poetry/core/tokens/color.rb +215 -0
- data/lib/poetry/core/tokens/contrast_gate.rb +120 -0
- data/lib/poetry/core/tokens/generator.rb +211 -0
- data/lib/poetry/core/tokens.rb +117 -0
- data/lib/poetry/core/version.rb +9 -0
- data/lib/poetry/core.rb +52 -0
- data/lib/poetry-core.rb +5 -0
- data/tokens/aliases.css +145 -0
- data/tokens/tailwind-theme.css +47 -0
- data/tokens/tokens.css +78 -0
- data/tokens/tokens.dtcg.json +779 -0
- data/vendor/floating-ui/LICENSE +20 -0
- data/vendor/floating-ui/VENDORED_VERSIONS +15 -0
- data/vendor/shadcn-tailwind/LICENSE +21 -0
- data/vendor/shadcn-tailwind/VENDORED_COMMIT +1 -0
- data/vendor/shadcn-tailwind/tailwind.css +629 -0
- data/vendor/tw-animate-css/LICENSE +21 -0
- data/vendor/tw-animate-css/VENDORED_VERSION +1 -0
- data/vendor/tw-animate-css/tw-animate.css +1 -0
- metadata +267 -0
data/config/importmap.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# poetry-core's importmap pins (the importmap-first channel): the
|
|
4
|
+
# host app's importmap merges these, so `import { registerPoetryControllers }
|
|
5
|
+
# from "@poetry/controllers"` works with zero build. Subpath specifiers
|
|
6
|
+
# (@poetry/controllers/helpers/state) resolve here via pin_all_from and in
|
|
7
|
+
# bundler hosts via the npm package's exports map - one source, two channels.
|
|
8
|
+
|
|
9
|
+
pin "@poetry/controllers", to: "poetry/core/index.js"
|
|
10
|
+
pin_all_from File.expand_path("../app/javascript/poetry/core", __dir__),
|
|
11
|
+
under: "@poetry/controllers", to: "poetry/core"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"keys": [
|
|
3
|
+
"active",
|
|
4
|
+
"checked",
|
|
5
|
+
"closed",
|
|
6
|
+
"inactive",
|
|
7
|
+
"indeterminate",
|
|
8
|
+
"open",
|
|
9
|
+
"panel-closed",
|
|
10
|
+
"panel-open",
|
|
11
|
+
"popup-closed",
|
|
12
|
+
"popup-open",
|
|
13
|
+
"pressed",
|
|
14
|
+
"selected",
|
|
15
|
+
"unchecked",
|
|
16
|
+
"unpressed",
|
|
17
|
+
"unselected"
|
|
18
|
+
],
|
|
19
|
+
"attributes": [
|
|
20
|
+
"data-active",
|
|
21
|
+
"data-checked",
|
|
22
|
+
"data-closed",
|
|
23
|
+
"data-indeterminate",
|
|
24
|
+
"data-open",
|
|
25
|
+
"data-panel-open",
|
|
26
|
+
"data-popup-open",
|
|
27
|
+
"data-pressed",
|
|
28
|
+
"data-selected",
|
|
29
|
+
"data-unchecked"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_model/type"
|
|
4
|
+
|
|
5
|
+
# Reopened to register poetry's option types alongside Rails' own.
|
|
6
|
+
module ActiveModel
|
|
7
|
+
# Reopened: poetry registers its list (and symbol) attribute types here
|
|
8
|
+
# so the option/style DSLs can declare them.
|
|
9
|
+
module Type
|
|
10
|
+
# A string-array option type (Accordion's open:, future multi-selects).
|
|
11
|
+
# Casts scalars to one-element arrays and stringifies members, so
|
|
12
|
+
# open: :shipping and open: %w[a b] both normalize.
|
|
13
|
+
class List < ActiveModel::Type::Value
|
|
14
|
+
# Reports :list to introspection (prop_definitions, the registry).
|
|
15
|
+
#
|
|
16
|
+
# @return [Symbol]
|
|
17
|
+
def type
|
|
18
|
+
:list
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Normalizes any value to an array of strings: nil becomes [], a
|
|
22
|
+
# scalar becomes a one-element array, and members are stringified.
|
|
23
|
+
#
|
|
24
|
+
# @param value [Object] the declared option value
|
|
25
|
+
# @return [Array<String>]
|
|
26
|
+
def cast(value)
|
|
27
|
+
return [] if value.nil?
|
|
28
|
+
|
|
29
|
+
Array(value).map(&:to_s)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_model/type"
|
|
4
|
+
|
|
5
|
+
module ActiveModel
|
|
6
|
+
module Type
|
|
7
|
+
# A symbol option type for the option DSL: casts anything responding
|
|
8
|
+
# to #to_sym and reports :symbol to introspection.
|
|
9
|
+
#
|
|
10
|
+
# Strict by design: a value that cannot become a Symbol raises at
|
|
11
|
+
# assignment - poetry surfaces bad option values where they are
|
|
12
|
+
# written, not as a validation error nothing reads at render.
|
|
13
|
+
# Leniency is List's job, not this type's.
|
|
14
|
+
class Symbol < ActiveModel::Type::String
|
|
15
|
+
# Without this the type reports :string (inherited) - introspection
|
|
16
|
+
# (prop_definitions, the registry) must see :symbol.
|
|
17
|
+
#
|
|
18
|
+
# @return [Symbol] :symbol
|
|
19
|
+
def type
|
|
20
|
+
:symbol
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Casts a value to a Symbol; nil stays nil.
|
|
24
|
+
#
|
|
25
|
+
# @param value [#to_sym, nil] the raw option value
|
|
26
|
+
# @return [Symbol, nil]
|
|
27
|
+
# @raise [ArgumentError] when the value cannot become a Symbol
|
|
28
|
+
def cast(value)
|
|
29
|
+
return nil if value.nil?
|
|
30
|
+
raise ArgumentError, "#{value.inspect} can't become a Symbol (no #to_sym)" unless value.respond_to?(:to_sym)
|
|
31
|
+
|
|
32
|
+
value.to_sym
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Poetry
|
|
4
|
+
module Core
|
|
5
|
+
module Check
|
|
6
|
+
# The StableId heuristics: two WARNING-severity rules over
|
|
7
|
+
# raw ERB text, each catching a render that escapes the per-request
|
|
8
|
+
# id story and therefore needs explicit identity (key: or id:).
|
|
9
|
+
#
|
|
10
|
+
# HEURISTIC, by design and by documentation: block extents are
|
|
11
|
+
# matched by scanning scriptlet openers/closers, which covers
|
|
12
|
+
# conventional ERB and misses exotic structure; cross-template
|
|
13
|
+
# composition (a cached partial rendering components defined
|
|
14
|
+
# elsewhere) is invisible to any static check - the dev-mode
|
|
15
|
+
# composed-DOM tripwire is the runtime complement.
|
|
16
|
+
#
|
|
17
|
+
# - stable-identity/cache: a poetry component inside a `<% cache %>`
|
|
18
|
+
# block without key:/id: freezes a random id into the fragment;
|
|
19
|
+
# replays can collide and morphs can't pair it.
|
|
20
|
+
# - stable-identity/collection: a poetry component inside an
|
|
21
|
+
# each/map loop without key:/id: gets a fresh random id per
|
|
22
|
+
# render, so Turbo morph replaces it on any reorder instead of
|
|
23
|
+
# following the record.
|
|
24
|
+
#
|
|
25
|
+
# A component whose registry entry declares "identity" => false
|
|
26
|
+
# renders no poetry-minted id - key:/id: would have nothing to
|
|
27
|
+
# stabilize - so both rules skip it. The registry derivation owns
|
|
28
|
+
# that fact per gem; legacy entries without the key keep warning.
|
|
29
|
+
#
|
|
30
|
+
# @api private
|
|
31
|
+
class StableIdentity
|
|
32
|
+
# A scriptlet that OPENS a Ruby block (needs its own <% end %>):
|
|
33
|
+
# trailing `do |...|`, or a non-modifier if/unless/case/begin.
|
|
34
|
+
BLOCK_OPENER =
|
|
35
|
+
/(?:\bdo\s*(?:\|[^|]*\|)?\s*\z)|(?:\A\s*(?:if|unless|case|while|until|for|begin)\b)/
|
|
36
|
+
CACHE_OPENER = /\A\s*cache[\s(]/
|
|
37
|
+
LOOP_OPENER =
|
|
38
|
+
/\.(?:each|each_with_index|each_with_object|each_slice|map|collect|flat_map)\b.*\bdo\b|\Afor\s.+\sin\s/
|
|
39
|
+
IDENTITY_ARG = /(?:\bkey:|\bid:|["']key["']\s*=>|["']id["']\s*=>)/
|
|
40
|
+
|
|
41
|
+
def initialize(catalog)
|
|
42
|
+
@catalog = catalog
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Returns [Finding] for one ERB source. Tracks a stack of open
|
|
46
|
+
# blocks (tagged cache/loop/other) and flags poetry helper calls
|
|
47
|
+
# rendered while a cache or loop frame is open.
|
|
48
|
+
def lint(source)
|
|
49
|
+
findings = []
|
|
50
|
+
stack = []
|
|
51
|
+
|
|
52
|
+
source.each_line.with_index(1) do |line, number|
|
|
53
|
+
line.scan(/<%(?:=|-)?\s*(.*?)\s*(?:-)?%>/m).each do |(code)|
|
|
54
|
+
next if code.nil?
|
|
55
|
+
|
|
56
|
+
flag_helpers(code, number, stack, findings)
|
|
57
|
+
|
|
58
|
+
if code.match?(/\A\s*end\b/)
|
|
59
|
+
stack.pop
|
|
60
|
+
elsif code.match?(BLOCK_OPENER)
|
|
61
|
+
stack << frame_for(code)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
findings
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def frame_for(code)
|
|
72
|
+
return :cache if code.match?(CACHE_OPENER)
|
|
73
|
+
return :loop if code.match?(LOOP_OPENER)
|
|
74
|
+
|
|
75
|
+
:other
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def flag_helpers(code, line, stack, findings)
|
|
79
|
+
code.scan(/\b(poetry_[a-z0-9_]+)\b/) do |(helper)|
|
|
80
|
+
next unless @catalog.helper?(helper)
|
|
81
|
+
next if @catalog.identity_free?(helper)
|
|
82
|
+
next if code.match?(IDENTITY_ARG)
|
|
83
|
+
|
|
84
|
+
if stack.include?(:cache)
|
|
85
|
+
findings << Finding.new(
|
|
86
|
+
rule: "stable-identity/cache", severity: :warning, line: line,
|
|
87
|
+
message: "#{helper} inside a cache block without key:/id: freezes a random id " \
|
|
88
|
+
"into the fragment - replays can collide and Turbo morph can't pair it " \
|
|
89
|
+
"(heuristic: block extents are scanned, not parsed)"
|
|
90
|
+
)
|
|
91
|
+
elsif stack.include?(:loop)
|
|
92
|
+
findings << Finding.new(
|
|
93
|
+
rule: "stable-identity/collection", severity: :warning, line: line,
|
|
94
|
+
message: "#{helper} inside a collection loop without key:/id: re-randomizes " \
|
|
95
|
+
"per render - a Turbo morph reorder replaces it instead of following " \
|
|
96
|
+
"the record; pass key: record (heuristic)"
|
|
97
|
+
)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|