weft 0.1.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 +7 -0
- data/CHANGELOG.md +37 -0
- data/LICENSE.txt +21 -0
- data/README.md +150 -0
- data/docs/app-patterns.md +268 -0
- data/docs/arbre.md +298 -0
- data/docs/configuration.md +219 -0
- data/docs/dsl.md +329 -0
- data/docs/error-handling.md +136 -0
- data/docs/examples/README.md +70 -0
- data/docs/examples/active-search.md +125 -0
- data/docs/examples/browser-dialogs.md +71 -0
- data/docs/examples/bulk-update.md +122 -0
- data/docs/examples/click-to-edit.md +113 -0
- data/docs/examples/click-to-load.md +77 -0
- data/docs/examples/delete-row.md +101 -0
- data/docs/examples/edit-row.md +146 -0
- data/docs/examples/file-upload.md +96 -0
- data/docs/examples/infinite-scroll.md +98 -0
- data/docs/examples/inline-expansion.md +98 -0
- data/docs/examples/inline-validation.md +101 -0
- data/docs/examples/keyboard-shortcuts.md +71 -0
- data/docs/examples/lazy-loading.md +96 -0
- data/docs/examples/live-ticker.md +91 -0
- data/docs/examples/modal-dialog.md +88 -0
- data/docs/examples/progress-bar.md +138 -0
- data/docs/examples/reset-user-input.md +101 -0
- data/docs/examples/tabs.md +102 -0
- data/docs/examples/tooltip.md +88 -0
- data/docs/examples/updating-other-content.md +169 -0
- data/docs/examples/value-select.md +109 -0
- data/docs/routing.md +131 -0
- data/docs/tutorial.md +372 -0
- data/lib/weft/action.rb +83 -0
- data/lib/weft/attributes.rb +65 -0
- data/lib/weft/component.rb +176 -0
- data/lib/weft/configuration.rb +177 -0
- data/lib/weft/context/interception.rb +22 -0
- data/lib/weft/context.rb +184 -0
- data/lib/weft/defaults/error_component.rb +63 -0
- data/lib/weft/defaults/error_page.rb +27 -0
- data/lib/weft/defaults/not_found_component.rb +44 -0
- data/lib/weft/defaults/not_found_page.rb +25 -0
- data/lib/weft/defaults.rb +9 -0
- data/lib/weft/dsl/actions.rb +72 -0
- data/lib/weft/dsl/attributes.rb +43 -0
- data/lib/weft/dsl/containers.rb +77 -0
- data/lib/weft/dsl/inclusions.rb +49 -0
- data/lib/weft/dsl/recoveries.rb +89 -0
- data/lib/weft/dsl/triggers.rb +40 -0
- data/lib/weft/dsl/updates.rb +86 -0
- data/lib/weft/error.rb +64 -0
- data/lib/weft/page.rb +371 -0
- data/lib/weft/redirect.rb +45 -0
- data/lib/weft/registry/eligibility.rb +58 -0
- data/lib/weft/registry.rb +202 -0
- data/lib/weft/resolver.rb +33 -0
- data/lib/weft/router/actions.rb +77 -0
- data/lib/weft/router/errors.rb +246 -0
- data/lib/weft/router/oob_includes.rb +34 -0
- data/lib/weft/router/streaming.rb +63 -0
- data/lib/weft/router.rb +191 -0
- data/lib/weft/shorthands.rb +57 -0
- data/lib/weft/version.rb +5 -0
- data/lib/weft.rb +124 -0
- metadata +169 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Weft
|
|
4
|
+
# Registry for named interaction shorthands. Each shorthand is a preset of
|
|
5
|
+
# trigger/swap/target defaults that Context expands via loads:.
|
|
6
|
+
#
|
|
7
|
+
# Shipped presets are registered at the bottom of this file. Users will be
|
|
8
|
+
# able to register custom shorthands in v1.x via the same API.
|
|
9
|
+
module Shorthands
|
|
10
|
+
class << self
|
|
11
|
+
# Register a named interaction shorthand.
|
|
12
|
+
#
|
|
13
|
+
# Weft::Shorthands.register :tooltip, trigger: :hover, swap: :fill
|
|
14
|
+
def register(name, **defaults)
|
|
15
|
+
registry[name] = defaults
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Look up a registered shorthand by name. Returns the defaults hash or nil.
|
|
19
|
+
def lookup(name)
|
|
20
|
+
registry[name]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# All registered shorthand names.
|
|
24
|
+
def registered
|
|
25
|
+
registry.keys
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def registry
|
|
31
|
+
@registry ||= {}
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Shipped interaction shorthands. Adding a new one is one line.
|
|
38
|
+
# The mechanism (Context dispatch + loads: expansion) handles the rest.
|
|
39
|
+
#
|
|
40
|
+
# NOTE: "shorthand" naming is provisional — may be renamed to "pattern"
|
|
41
|
+
# or similar after evaluation (Mission 29).
|
|
42
|
+
|
|
43
|
+
Weft::Shorthands.register :tooltip, trigger: :hover, swap: :fill
|
|
44
|
+
Weft::Shorthands.register :inline_expand, trigger: :click, swap: :after
|
|
45
|
+
Weft::Shorthands.register :lazy, trigger: :visible, swap: :fill, target: :self
|
|
46
|
+
Weft::Shorthands.register :modal, trigger: :click, swap: :fill
|
|
47
|
+
Weft::Shorthands.register :load_more, trigger: :click, swap: :replace, target: :self
|
|
48
|
+
Weft::Shorthands.register :infinite_scroll, trigger: :visible, swap: :after
|
|
49
|
+
Weft::Shorthands.register :live_search, trigger: :input, swap: :fill
|
|
50
|
+
Weft::Shorthands.register :tabs, trigger: :click, swap: :fill
|
|
51
|
+
|
|
52
|
+
# Retry is the odd one out: its value is a URL (the failing component's own GET
|
|
53
|
+
# URL, injected as the :retry_url recovery attr), not a target Class. It ships a
|
|
54
|
+
# concrete hx-target so error components never hand-write htmx — outerHTML-swapping
|
|
55
|
+
# the enclosing .weft-error box replaces the whole error display with the fresh
|
|
56
|
+
# component. Callers override target: for a differently-classed container.
|
|
57
|
+
Weft::Shorthands.register :retry, trigger: :click, swap: :outer_html, target: "closest .weft-error"
|
data/lib/weft/version.rb
ADDED
data/lib/weft.rb
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "logger"
|
|
4
|
+
|
|
5
|
+
require "active_support"
|
|
6
|
+
require "active_support/core_ext/integer/time"
|
|
7
|
+
require "active_support/core_ext/string/inflections"
|
|
8
|
+
require "arbre"
|
|
9
|
+
|
|
10
|
+
require "weft/error"
|
|
11
|
+
require "weft/attributes"
|
|
12
|
+
require "weft/dsl/attributes"
|
|
13
|
+
require "weft/dsl/recoveries"
|
|
14
|
+
require "weft/dsl/triggers"
|
|
15
|
+
require "weft/dsl/inclusions"
|
|
16
|
+
require "weft/dsl/updates"
|
|
17
|
+
require "weft/dsl/actions"
|
|
18
|
+
require "weft/dsl/containers"
|
|
19
|
+
require "weft/configuration"
|
|
20
|
+
require "weft/registry"
|
|
21
|
+
require "weft/registry/eligibility"
|
|
22
|
+
require "weft/action"
|
|
23
|
+
require "weft/component"
|
|
24
|
+
require "weft/context"
|
|
25
|
+
require "weft/resolver"
|
|
26
|
+
require "weft/page"
|
|
27
|
+
require "weft/redirect"
|
|
28
|
+
require "weft/router"
|
|
29
|
+
require "weft/version"
|
|
30
|
+
|
|
31
|
+
# Component-oriented hypermedia for Ruby.
|
|
32
|
+
module Weft
|
|
33
|
+
class << self
|
|
34
|
+
attr_writer :logger
|
|
35
|
+
|
|
36
|
+
# Weft's process-wide logger. In standalone mode this defaults to a $stdout
|
|
37
|
+
# Logger at the configured log_level (:info by default) — modeling the
|
|
38
|
+
# unified activity+error stream a 12-factor Rails container emits under
|
|
39
|
+
# RAILS_LOG_TO_STDOUT, so deployments aggregate it like any other web
|
|
40
|
+
# container. When mounted in Rails, set +Weft.logger = Rails.logger+ and
|
|
41
|
+
# this default never applies. Weft.configure applies log_level to it.
|
|
42
|
+
def logger
|
|
43
|
+
@logger ||= Logger.new($stdout)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def configuration
|
|
47
|
+
@configuration ||= Configuration.new
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def registry
|
|
51
|
+
@registry ||= Registry.new
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def configure
|
|
55
|
+
yield configuration
|
|
56
|
+
apply_configuration
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Convenience wrapper for Weft::Redirect.to.
|
|
60
|
+
def redirect(target, **attrs)
|
|
61
|
+
Redirect.to(target, **attrs)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Register a named interaction shorthand. Delegates to Weft::Shorthands.
|
|
65
|
+
#
|
|
66
|
+
# Weft.register_shorthand :tooltip, trigger: :hover, swap: :fill
|
|
67
|
+
def register_shorthand(name, **defaults)
|
|
68
|
+
Shorthands.register(name, **defaults)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Look up a registered shorthand by name. Delegates to Weft::Shorthands.
|
|
72
|
+
def shorthand(name)
|
|
73
|
+
Shorthands.lookup(name)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
# Apply side-effects from the current Weft.configuration. Called by
|
|
79
|
+
# Weft.configure after the user block yields. Safe to call multiple
|
|
80
|
+
# times — each apply step is idempotent.
|
|
81
|
+
def apply_configuration
|
|
82
|
+
logger.level = configuration.resolved_log_level
|
|
83
|
+
Router.set(:logging, configuration.router_logging)
|
|
84
|
+
enable_auto_reload! if configuration.auto_reload && !@auto_reload_applied
|
|
85
|
+
apply_static_assets!
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def enable_auto_reload!
|
|
89
|
+
require "sinatra/reloader"
|
|
90
|
+
Router.register(Sinatra::Reloader)
|
|
91
|
+
configuration.reload_paths.each { |path| Router.also_reload(path) }
|
|
92
|
+
@auto_reload_applied = true
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def apply_static_assets!
|
|
96
|
+
@mounted_static_bundles ||= Set.new
|
|
97
|
+
configuration.static_assets.each do |name, bundle|
|
|
98
|
+
next if @mounted_static_bundles.include?(name)
|
|
99
|
+
|
|
100
|
+
mount_static_assets_route(bundle[:root], bundle[:from])
|
|
101
|
+
@mounted_static_bundles << name
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Mount a Sinatra before-filter that serves files under `from` at the URL
|
|
106
|
+
# prefix `root`. send_file handles content-type/etag/halt; the expand-
|
|
107
|
+
# path containment check rejects path-traversal attempts (e.g.
|
|
108
|
+
# /static/../../etc/passwd resolves outside `from` and returns 404).
|
|
109
|
+
def mount_static_assets_route(root, from)
|
|
110
|
+
expanded_from = File.expand_path(from)
|
|
111
|
+
Router.before "#{root}/*" do
|
|
112
|
+
next unless request.get? || request.head?
|
|
113
|
+
|
|
114
|
+
requested = File.expand_path(params[:splat].first, expanded_from)
|
|
115
|
+
halt 404 unless requested.start_with?("#{expanded_from}/") && File.file?(requested)
|
|
116
|
+
|
|
117
|
+
send_file requested
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
require "weft/shorthands"
|
|
124
|
+
require "weft/defaults"
|
metadata
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: weft
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Andy Rusterholz
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-07-12 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activesupport
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '6.1'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '6.1'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: arbre
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.7'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.7'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: sinatra
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: sinatra-contrib
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '3.0'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '3.0'
|
|
69
|
+
description: Weft is a rapid web development framework where front-end components
|
|
70
|
+
declare what behaviors are possible, and the back-end routing and request handling
|
|
71
|
+
is derived automatically. No routes. No controllers. Just Weft.
|
|
72
|
+
email:
|
|
73
|
+
- andyrusterholz@gmail.com
|
|
74
|
+
executables: []
|
|
75
|
+
extensions: []
|
|
76
|
+
extra_rdoc_files: []
|
|
77
|
+
files:
|
|
78
|
+
- CHANGELOG.md
|
|
79
|
+
- LICENSE.txt
|
|
80
|
+
- README.md
|
|
81
|
+
- docs/app-patterns.md
|
|
82
|
+
- docs/arbre.md
|
|
83
|
+
- docs/configuration.md
|
|
84
|
+
- docs/dsl.md
|
|
85
|
+
- docs/error-handling.md
|
|
86
|
+
- docs/examples/README.md
|
|
87
|
+
- docs/examples/active-search.md
|
|
88
|
+
- docs/examples/browser-dialogs.md
|
|
89
|
+
- docs/examples/bulk-update.md
|
|
90
|
+
- docs/examples/click-to-edit.md
|
|
91
|
+
- docs/examples/click-to-load.md
|
|
92
|
+
- docs/examples/delete-row.md
|
|
93
|
+
- docs/examples/edit-row.md
|
|
94
|
+
- docs/examples/file-upload.md
|
|
95
|
+
- docs/examples/infinite-scroll.md
|
|
96
|
+
- docs/examples/inline-expansion.md
|
|
97
|
+
- docs/examples/inline-validation.md
|
|
98
|
+
- docs/examples/keyboard-shortcuts.md
|
|
99
|
+
- docs/examples/lazy-loading.md
|
|
100
|
+
- docs/examples/live-ticker.md
|
|
101
|
+
- docs/examples/modal-dialog.md
|
|
102
|
+
- docs/examples/progress-bar.md
|
|
103
|
+
- docs/examples/reset-user-input.md
|
|
104
|
+
- docs/examples/tabs.md
|
|
105
|
+
- docs/examples/tooltip.md
|
|
106
|
+
- docs/examples/updating-other-content.md
|
|
107
|
+
- docs/examples/value-select.md
|
|
108
|
+
- docs/routing.md
|
|
109
|
+
- docs/tutorial.md
|
|
110
|
+
- lib/weft.rb
|
|
111
|
+
- lib/weft/action.rb
|
|
112
|
+
- lib/weft/attributes.rb
|
|
113
|
+
- lib/weft/component.rb
|
|
114
|
+
- lib/weft/configuration.rb
|
|
115
|
+
- lib/weft/context.rb
|
|
116
|
+
- lib/weft/context/interception.rb
|
|
117
|
+
- lib/weft/defaults.rb
|
|
118
|
+
- lib/weft/defaults/error_component.rb
|
|
119
|
+
- lib/weft/defaults/error_page.rb
|
|
120
|
+
- lib/weft/defaults/not_found_component.rb
|
|
121
|
+
- lib/weft/defaults/not_found_page.rb
|
|
122
|
+
- lib/weft/dsl/actions.rb
|
|
123
|
+
- lib/weft/dsl/attributes.rb
|
|
124
|
+
- lib/weft/dsl/containers.rb
|
|
125
|
+
- lib/weft/dsl/inclusions.rb
|
|
126
|
+
- lib/weft/dsl/recoveries.rb
|
|
127
|
+
- lib/weft/dsl/triggers.rb
|
|
128
|
+
- lib/weft/dsl/updates.rb
|
|
129
|
+
- lib/weft/error.rb
|
|
130
|
+
- lib/weft/page.rb
|
|
131
|
+
- lib/weft/redirect.rb
|
|
132
|
+
- lib/weft/registry.rb
|
|
133
|
+
- lib/weft/registry/eligibility.rb
|
|
134
|
+
- lib/weft/resolver.rb
|
|
135
|
+
- lib/weft/router.rb
|
|
136
|
+
- lib/weft/router/actions.rb
|
|
137
|
+
- lib/weft/router/errors.rb
|
|
138
|
+
- lib/weft/router/oob_includes.rb
|
|
139
|
+
- lib/weft/router/streaming.rb
|
|
140
|
+
- lib/weft/shorthands.rb
|
|
141
|
+
- lib/weft/version.rb
|
|
142
|
+
homepage: https://github.com/rusterholz/weft
|
|
143
|
+
licenses:
|
|
144
|
+
- MIT
|
|
145
|
+
metadata:
|
|
146
|
+
homepage_uri: https://github.com/rusterholz/weft
|
|
147
|
+
source_code_uri: https://github.com/rusterholz/weft
|
|
148
|
+
changelog_uri: https://github.com/rusterholz/weft/blob/main/CHANGELOG.md
|
|
149
|
+
rubygems_mfa_required: 'true'
|
|
150
|
+
post_install_message:
|
|
151
|
+
rdoc_options: []
|
|
152
|
+
require_paths:
|
|
153
|
+
- lib
|
|
154
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
155
|
+
requirements:
|
|
156
|
+
- - ">="
|
|
157
|
+
- !ruby/object:Gem::Version
|
|
158
|
+
version: 3.2.0
|
|
159
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
|
+
requirements:
|
|
161
|
+
- - ">="
|
|
162
|
+
- !ruby/object:Gem::Version
|
|
163
|
+
version: '0'
|
|
164
|
+
requirements: []
|
|
165
|
+
rubygems_version: 3.5.22
|
|
166
|
+
signing_key:
|
|
167
|
+
specification_version: 4
|
|
168
|
+
summary: Component-oriented hypermedia for Ruby.
|
|
169
|
+
test_files: []
|