|
44 | 44 | function findParentTreeNode(node) { |
45 | 45 | if (node == null || !(node instanceof HTMLElement)) return null; |
46 | 46 | if (node.classList.contains("bx--tree-parent-node")) return node; |
| 47 | + if (node.classList.contains("bx--tree-node-link-parent")) { |
| 48 | + return node.firstElementChild; |
| 49 | + } |
47 | 50 | if (node.classList.contains("bx--tree")) return null; |
48 | 51 | if (node.parentNode instanceof HTMLElement) { |
49 | 52 | return findParentTreeNode(node.parentNode); |
|
66 | 69 | export let text = ""; |
67 | 70 | export let disabled = false; |
68 | 71 |
|
| 72 | + /** |
| 73 | + * Specify the URL the TreeNode links to. |
| 74 | + * @type {string | undefined} |
| 75 | + */ |
| 76 | + export let href = undefined; |
| 77 | +
|
| 78 | + /** |
| 79 | + * Specify the link target. |
| 80 | + * @type {string | undefined} |
| 81 | + */ |
| 82 | + export let target = undefined; |
| 83 | +
|
69 | 84 | /** |
70 | 85 | * Specify the icon to render. |
71 | 86 | * @type {Icon} |
|
112 | 127 | } |
113 | 128 | </script> |
114 | 129 |
|
115 | | -<!-- svelte-ignore a11y-no-noninteractive-element-to-interactive-role --> |
116 | | -<li |
117 | | - bind:this={ref} |
118 | | - role="treeitem" |
119 | | - {id} |
120 | | - tabindex={disabled ? undefined : -1} |
121 | | - aria-current={id === $activeNodeId || undefined} |
122 | | - aria-selected={disabled ? undefined : selected} |
123 | | - aria-disabled={disabled} |
124 | | - class:bx--tree-node={true} |
125 | | - class:bx--tree-leaf-node={true} |
126 | | - class:bx--tree-node--active={id === $activeNodeId} |
127 | | - class:bx--tree-node--selected={selected} |
128 | | - class:bx--tree-node--disabled={disabled} |
129 | | - class:bx--tree-node--with-icon={icon} |
130 | | - on:click|stopPropagation={() => { |
131 | | - if (disabled) return; |
132 | | - clickNode(node); |
133 | | - }} |
134 | | - on:keydown={(e) => { |
135 | | - if (e.key === "ArrowLeft" || e.key === "ArrowRight" || e.key === "Enter") { |
136 | | - e.stopPropagation(); |
137 | | - } |
138 | | - |
139 | | - if (e.key === "ArrowLeft") { |
140 | | - const parentNode = findParentTreeNode(ref.parentNode); |
141 | | - if (parentNode) parentNode.focus(); |
142 | | - } |
143 | | - |
144 | | - if (e.key === "Enter" || e.key === " ") { |
145 | | - e.preventDefault(); |
| 130 | +{#if href} |
| 131 | + <li role="none"> |
| 132 | + <!-- svelte-ignore a11y-no-noninteractive-element-to-interactive-role a11y-role-has-required-aria-props --> |
| 133 | + <a |
| 134 | + bind:this={ref} |
| 135 | + role="treeitem" |
| 136 | + {id} |
| 137 | + href={disabled ? undefined : href} |
| 138 | + target={disabled ? undefined : target} |
| 139 | + rel={target === "_blank" ? "noopener noreferrer" : undefined} |
| 140 | + tabindex={disabled ? undefined : -1} |
| 141 | + aria-current={id === $activeNodeId ? "page" : undefined} |
| 142 | + aria-disabled={disabled} |
| 143 | + class:bx--tree-node={true} |
| 144 | + class:bx--tree-leaf-node={true} |
| 145 | + class:bx--tree-node--active={id === $activeNodeId} |
| 146 | + class:bx--tree-node--selected={selected} |
| 147 | + class:bx--tree-node--disabled={disabled} |
| 148 | + class:bx--tree-node--with-icon={icon} |
| 149 | + on:click|stopPropagation={() => { |
| 150 | + if (disabled) return; |
| 151 | + clickNode(node); |
| 152 | + }} |
| 153 | + on:keydown={(e) => { |
| 154 | + if ( |
| 155 | + e.key === "ArrowLeft" || |
| 156 | + e.key === "ArrowRight" || |
| 157 | + e.key === "Enter" |
| 158 | + ) { |
| 159 | + e.stopPropagation(); |
| 160 | + } |
| 161 | + |
| 162 | + if (e.key === "ArrowLeft") { |
| 163 | + const parentNode = findParentTreeNode(ref.parentNode?.parentNode); |
| 164 | + if (parentNode) parentNode.focus(); |
| 165 | + } |
| 166 | + |
| 167 | + if (e.key === "Enter" || e.key === " ") { |
| 168 | + e.preventDefault(); |
| 169 | + if (disabled) return; |
| 170 | + clickNode(node); |
| 171 | + } |
| 172 | + }} |
| 173 | + on:focus={() => { |
| 174 | + focusNode(node); |
| 175 | + }} |
| 176 | + > |
| 177 | + <div bind:this={refLabel} class:bx--tree-node__label={true}> |
| 178 | + <svelte:component this={icon} class="bx--tree-node__icon" /> |
| 179 | + <slot {node}> {text} </slot> |
| 180 | + </div> |
| 181 | + </a> |
| 182 | + </li> |
| 183 | +{:else} |
| 184 | + <!-- svelte-ignore a11y-no-noninteractive-element-to-interactive-role --> |
| 185 | + <li |
| 186 | + bind:this={ref} |
| 187 | + role="treeitem" |
| 188 | + {id} |
| 189 | + tabindex={disabled ? undefined : -1} |
| 190 | + aria-current={id === $activeNodeId || undefined} |
| 191 | + aria-selected={disabled ? undefined : selected} |
| 192 | + aria-disabled={disabled} |
| 193 | + class:bx--tree-node={true} |
| 194 | + class:bx--tree-leaf-node={true} |
| 195 | + class:bx--tree-node--active={id === $activeNodeId} |
| 196 | + class:bx--tree-node--selected={selected} |
| 197 | + class:bx--tree-node--disabled={disabled} |
| 198 | + class:bx--tree-node--with-icon={icon} |
| 199 | + on:click|stopPropagation={() => { |
146 | 200 | if (disabled) return; |
147 | 201 | clickNode(node); |
148 | | - } |
149 | | - }} |
150 | | - on:focus={() => { |
151 | | - focusNode(node); |
152 | | - }} |
153 | | -> |
154 | | - <div bind:this={refLabel} class:bx--tree-node__label={true}> |
155 | | - <svelte:component this={icon} class="bx--tree-node__icon" /> |
156 | | - <slot {node}> {text} </slot> |
157 | | - </div> |
158 | | -</li> |
| 202 | + }} |
| 203 | + on:keydown={(e) => { |
| 204 | + if ( |
| 205 | + e.key === "ArrowLeft" || |
| 206 | + e.key === "ArrowRight" || |
| 207 | + e.key === "Enter" |
| 208 | + ) { |
| 209 | + e.stopPropagation(); |
| 210 | + } |
| 211 | + |
| 212 | + if (e.key === "ArrowLeft") { |
| 213 | + const parentNode = findParentTreeNode(ref.parentNode); |
| 214 | + if (parentNode) parentNode.focus(); |
| 215 | + } |
| 216 | + |
| 217 | + if (e.key === "Enter" || e.key === " ") { |
| 218 | + e.preventDefault(); |
| 219 | + if (disabled) return; |
| 220 | + clickNode(node); |
| 221 | + } |
| 222 | + }} |
| 223 | + on:focus={() => { |
| 224 | + focusNode(node); |
| 225 | + }} |
| 226 | + > |
| 227 | + <div bind:this={refLabel} class:bx--tree-node__label={true}> |
| 228 | + <svelte:component this={icon} class="bx--tree-node__icon" /> |
| 229 | + <slot {node}> {text} </slot> |
| 230 | + </div> |
| 231 | + </li> |
| 232 | +{/if} |
0 commit comments