@barefootjs/perl 0.9.2 → 0.9.4
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.
- package/lib/BarefootJS.pm +59 -1
- package/package.json +1 -1
package/lib/BarefootJS.pm
CHANGED
|
@@ -52,10 +52,11 @@ my %ATTR_DEFAULT = (
|
|
|
52
52
|
# _scope_id — addressable scope id
|
|
53
53
|
# _bf_parent / _bf_mount — slot identity when this scope is slot-attached
|
|
54
54
|
# _props — props serialised into bf-p / the scope comment
|
|
55
|
+
# _data_key — keyed-loop-item key, emitted as data-key on the scope root
|
|
55
56
|
for my $attr (qw(
|
|
56
57
|
c config backend
|
|
57
58
|
_scripts _script_seen _scope_id _is_child _bf_parent _bf_mount _props
|
|
58
|
-
_child_renderers
|
|
59
|
+
_data_key _child_renderers
|
|
59
60
|
)) {
|
|
60
61
|
no strict 'refs';
|
|
61
62
|
*{"BarefootJS::$attr"} = sub {
|
|
@@ -131,6 +132,20 @@ sub hydration_attrs ($self) {
|
|
|
131
132
|
return join(' ', @parts);
|
|
132
133
|
}
|
|
133
134
|
|
|
135
|
+
# Emits ` data-key="<key>"` for a keyed loop item, else ''. The client
|
|
136
|
+
# runtime uses data-key for list reconciliation; SSR must match the Hono
|
|
137
|
+
# reference, which stamps it on each loop item's scope root. The value is set
|
|
138
|
+
# on the child instance by the child renderer (`register_child_renderer` /
|
|
139
|
+
# `register_components_from_manifest`) from the JSX `key` prop — a reserved
|
|
140
|
+
# prop, never a real template variable.
|
|
141
|
+
sub data_key_attr ($self) {
|
|
142
|
+
my $k = $self->_data_key;
|
|
143
|
+
return '' unless defined $k;
|
|
144
|
+
$k =~ s/&/&/g;
|
|
145
|
+
$k =~ s/"/"/g;
|
|
146
|
+
return qq{ data-key="$k"};
|
|
147
|
+
}
|
|
148
|
+
|
|
134
149
|
sub props_attr ($self) {
|
|
135
150
|
my $props = $self->_props;
|
|
136
151
|
return '' unless $props && %$props;
|
|
@@ -140,6 +155,45 @@ sub props_attr ($self) {
|
|
|
140
155
|
return qq{ bf-p='$json'};
|
|
141
156
|
}
|
|
142
157
|
|
|
158
|
+
# ---------------------------------------------------------------------------
|
|
159
|
+
# Context (SSR mirror of the client `provideContext` / `useContext`)
|
|
160
|
+
# ---------------------------------------------------------------------------
|
|
161
|
+
#
|
|
162
|
+
# A `<Ctx.Provider value>` seeds a value that descendant `useContext(Ctx)`
|
|
163
|
+
# consumers read during the same render. Dynamic scoping mirrors the client:
|
|
164
|
+
# the provider pushes the value before rendering its children and pops it
|
|
165
|
+
# after, and `use_context` reads the innermost active value (or the
|
|
166
|
+
# `createContext` default when none is active).
|
|
167
|
+
#
|
|
168
|
+
# The value stacks live in a package-level store rather than per-instance or
|
|
169
|
+
# on `$c->stash`: a parent template and the child templates it renders via
|
|
170
|
+
# `render_child` are separate bf instances that don't reliably share a
|
|
171
|
+
# controller (the Xslate backend runs with `c => undef`) nor a backend (the
|
|
172
|
+
# Mojo path lazily builds one per instance). SSR rendering is synchronous —
|
|
173
|
+
# nothing awaits between a provider's push and its matching pop — and the
|
|
174
|
+
# push/pop are perfectly balanced, so the per-name stack always unwinds to
|
|
175
|
+
# empty at the end of each provider subtree, keeping concurrent root renders
|
|
176
|
+
# isolated. provide/revoke return '' so they drop cleanly into an inline
|
|
177
|
+
# `<: … :>` (Kolon) or `% … ;` (EP) emit.
|
|
178
|
+
|
|
179
|
+
my %CONTEXT_STACKS;
|
|
180
|
+
|
|
181
|
+
sub provide_context ($self, $name, $value) {
|
|
182
|
+
push @{ $CONTEXT_STACKS{$name} //= [] }, $value;
|
|
183
|
+
return '';
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
sub revoke_context ($self, $name) {
|
|
187
|
+
pop @{ $CONTEXT_STACKS{$name} } if $CONTEXT_STACKS{$name} && @{ $CONTEXT_STACKS{$name} };
|
|
188
|
+
return '';
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
sub use_context ($self, $name, $default = undef) {
|
|
192
|
+
my $stack = $CONTEXT_STACKS{$name};
|
|
193
|
+
return $default unless $stack && @$stack;
|
|
194
|
+
return $stack->[-1];
|
|
195
|
+
}
|
|
196
|
+
|
|
143
197
|
# ---------------------------------------------------------------------------
|
|
144
198
|
# Comment Markers
|
|
145
199
|
# ---------------------------------------------------------------------------
|
|
@@ -299,6 +353,10 @@ sub register_components_from_manifest ($self, $manifest, %opts) {
|
|
|
299
353
|
# closure adds no edge to the per-request reference cycle.
|
|
300
354
|
my $child_bf = BarefootJS->new($parent->c, { backend => $parent->backend });
|
|
301
355
|
my $slot_id = delete $props->{_bf_slot};
|
|
356
|
+
# JSX `key` (a reserved prop) → data-key on the child's scope root
|
|
357
|
+
# for keyed-loop reconciliation (see `data_key_attr`).
|
|
358
|
+
my $data_key = delete $props->{key};
|
|
359
|
+
$child_bf->_data_key($data_key) if defined $data_key;
|
|
302
360
|
$child_bf->_scope_id(
|
|
303
361
|
$slot_id ? $parent_scope . '_' . $slot_id
|
|
304
362
|
: $template_name . '_' . substr(rand() =~ s/^0\.//r, 0, 6)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/perl",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.4",
|
|
4
4
|
"description": "BarefootJS engine-agnostic Perl runtime (BarefootJS.pm) — pluggable rendering backend; the shared basis for Mojolicious and other Perl framework integrations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|