Skip to content

Commit 8abcb89

Browse files
authored
Merge pull request #5 from BeastyBlacksmith/bbs/index-by-id
move indexing from Dash.jl
2 parents c2a9d6b + 3a6c7fe commit 8abcb89

File tree

2 files changed

+62
-23
lines changed

2 files changed

+62
-23
lines changed

src/components.jl

+29-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
to_dash(t::Any) = t
22

3-
struct Component
3+
struct Component
44
name ::String
55
type ::String
66
namespace ::String
@@ -9,9 +9,9 @@ struct Component
99
wildcard_regex ::Union{Nothing, Regex}
1010
function Component(name::String, type::String, namespace::String,
1111
props::Vector{Symbol}, wildcard_props::Vector{Symbol}; kwargs...)
12-
12+
1313
available_props = Set{Symbol}(props)
14-
wildcard_regex::Union{Nothing, Regex} = nothing
14+
wildcard_regex::Union{Nothing, Regex} = nothing
1515
if !isempty(wildcard_props)
1616
wildcard_regex = Regex(join(string.(wildcard_props), "|"))
1717
end
@@ -30,13 +30,36 @@ get_available_props(comp::Component) = getfield(comp, :available_props)
3030
get_wildcard_regex(comp::Component) = getfield(comp, :wildcard_regex)
3131
get_props(comp::Component) = getfield(comp, :props)
3232

33-
function Base.getproperty(comp::Component, prop::Symbol)
33+
const VecChildTypes = Union{NTuple{N, Component} where {N}, Vector{<:Component}}
34+
35+
function Base.getindex(component::Component, id::AbstractString)
36+
component.id == id && return component
37+
hasproperty(component, :children) || return nothing
38+
cc = component.children
39+
return if cc isa Union{VecChildTypes, DashBase.Component}
40+
cc[id]
41+
elseif cc isa AbstractVector
42+
fcc = identity.(filter(x->hasproperty(x, :id), cc))
43+
isempty(fcc) ? nothing : fcc[id]
44+
else
45+
nothing
46+
end
47+
end
48+
function Base.getindex(children::VecChildTypes, id::AbstractString)
49+
for element in children
50+
element.id == id && return element
51+
el = element[id]
52+
el !== nothing && return el
53+
end
54+
end
55+
56+
function Base.getproperty(comp::Component, prop::Symbol)
3457
!Base.hasproperty(comp, prop) && error("Component $(get_name(comp)) has no property $(prop)")
3558
props = get_props(comp)
3659
return haskey(props, prop) ? props[prop] : nothing
3760
end
3861

39-
function Base.setproperty!(comp::Component, prop::Symbol, value)
62+
function Base.setproperty!(comp::Component, prop::Symbol, value)
4063
!Base.hasproperty(comp, prop) && error("Component $(get_name(comp)) has no property $(prop)")
4164
props = get_props(comp)
4265
push!(props, prop=>to_dash(value))
@@ -56,4 +79,4 @@ Base.propertynames(comp::Component) = collect(get_available_props(comp))
5679
push_prop!(component::Component, prop::Symbol, value) = push!(component.props, prop=>to_dash(value))
5780

5881
JSON3.StructTypes.StructType(::Type{DashBase.Component}) = JSON3.StructTypes.Struct()
59-
JSON3.StructTypes.excludes(::Type{DashBase.Component}) = (:name, :available_props, :wildcard_regex)
82+
JSON3.StructTypes.excludes(::Type{DashBase.Component}) = (:name, :available_props, :wildcard_regex)

test/components.jl

+33-17
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ using JSON3
33

44
@testset "components creation" begin
55
test_comp = Component("html_div", "Div", "dash_html_components",
6-
[:children, :id, :n_clicks],
7-
[Symbol("data-"), Symbol("aria-")];
8-
id = 10,
9-
n_clicks = 1
10-
)
11-
6+
[:children, :id, :n_clicks],
7+
[Symbol("data-"), Symbol("aria-")];
8+
id=10,
9+
n_clicks=1
10+
)
11+
1212
@test get_name(test_comp) == "html_div"
1313
@test get_type(test_comp) == "Div"
1414
@test get_namespace(test_comp) == "dash_html_components"
@@ -24,11 +24,11 @@ using JSON3
2424
@test_throws ErrorException test_comp.key
2525
@test_throws ErrorException test_comp.key = 20
2626
@test_throws ErrorException Component("html_div", "Div", "dash_html_components",
27-
[:children, :id, :n_clicks],
28-
[Symbol("data-"), Symbol("aria-")];
29-
id = 10,
30-
key = 1
31-
)
27+
[:children, :id, :n_clicks],
28+
[Symbol("data-"), Symbol("aria-")];
29+
id=10,
30+
key=1
31+
)
3232
json = JSON3.write(test_comp)
3333
res = JSON3.read(json)
3434
@test all(keys(res) .== [:type, :namespace, :props])
@@ -40,11 +40,11 @@ end
4040

4141
@testset "empty wilds" begin
4242
test_comp = Component("html_div", "Div", "dash_html_components",
43-
[:children, :id, :n_clicks],
44-
Symbol[];
45-
id = 10,
46-
n_clicks = 1
47-
)
43+
[:children, :id, :n_clicks],
44+
Symbol[];
45+
id=10,
46+
n_clicks=1
47+
)
4848

4949
@test get_name(test_comp) == "html_div"
5050
@test get_type(test_comp) == "Div"
@@ -54,4 +54,20 @@ end
5454

5555
@test_throws ErrorException test_comp.var"data-id" = 20
5656
@test_throws ErrorException test_comp.aaaaa
57-
end
57+
end
58+
function test_component(; kwargs...)
59+
Component("html_div", "Div", "dash_html_components", [:dir, :n_clicks, :key, :loading_state, :contentEditable, :contextMenu, :n_clicks_timestamp, :draggable, :accessKey, :hidden, :style, :children, :id, :title, :role, :lang, :spellCheck, :tabIndex, :disable_n_clicks, :className], Symbol[]; kwargs...)
60+
end
61+
@testset "Index by id" begin
62+
layout = test_component(children=[
63+
test_component(id="my-id", n_clicks=0, title="text"),
64+
test_component(id="my-div", children=[
65+
test_component(children=[]),
66+
"string",
67+
test_component(id="target")
68+
]),
69+
test_component(id="my-div2")
70+
])
71+
@test layout["target"].id == "target"
72+
@test layout["ups"] === nothing
73+
end

0 commit comments

Comments
 (0)