@orange-halo/components 1.0.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.
- package/custom-elements.json +186 -0
- package/dist/base.d.ts +30 -0
- package/dist/base.d.ts.map +1 -0
- package/dist/base.js +78 -0
- package/dist/base.js.map +1 -0
- package/dist/index.d.ts +83 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/oh-accordion.d.ts +47 -0
- package/dist/oh-accordion.d.ts.map +1 -0
- package/dist/oh-accordion.js +387 -0
- package/dist/oh-accordion.js.map +1 -0
- package/dist/oh-alert.d.ts +48 -0
- package/dist/oh-alert.d.ts.map +1 -0
- package/dist/oh-alert.js +343 -0
- package/dist/oh-alert.js.map +1 -0
- package/dist/oh-badge.d.ts +38 -0
- package/dist/oh-badge.d.ts.map +1 -0
- package/dist/oh-badge.js +176 -0
- package/dist/oh-badge.js.map +1 -0
- package/dist/oh-breadcrumb.d.ts +39 -0
- package/dist/oh-breadcrumb.d.ts.map +1 -0
- package/dist/oh-breadcrumb.js +277 -0
- package/dist/oh-breadcrumb.js.map +1 -0
- package/dist/oh-button.d.ts +62 -0
- package/dist/oh-button.d.ts.map +1 -0
- package/dist/oh-button.figma.d.ts +2 -0
- package/dist/oh-button.figma.d.ts.map +1 -0
- package/dist/oh-button.figma.js +20 -0
- package/dist/oh-button.figma.js.map +1 -0
- package/dist/oh-button.js +490 -0
- package/dist/oh-button.js.map +1 -0
- package/dist/oh-card.d.ts +44 -0
- package/dist/oh-card.d.ts.map +1 -0
- package/dist/oh-card.js +340 -0
- package/dist/oh-card.js.map +1 -0
- package/dist/oh-checkbox-group.d.ts +39 -0
- package/dist/oh-checkbox-group.d.ts.map +1 -0
- package/dist/oh-checkbox-group.figma.d.ts +2 -0
- package/dist/oh-checkbox-group.figma.d.ts.map +1 -0
- package/dist/oh-checkbox-group.figma.js +24 -0
- package/dist/oh-checkbox-group.figma.js.map +1 -0
- package/dist/oh-checkbox-group.js +309 -0
- package/dist/oh-checkbox-group.js.map +1 -0
- package/dist/oh-checkbox.d.ts +50 -0
- package/dist/oh-checkbox.d.ts.map +1 -0
- package/dist/oh-checkbox.js +315 -0
- package/dist/oh-checkbox.js.map +1 -0
- package/dist/oh-cluster.d.ts +38 -0
- package/dist/oh-cluster.d.ts.map +1 -0
- package/dist/oh-cluster.js +141 -0
- package/dist/oh-cluster.js.map +1 -0
- package/dist/oh-container.d.ts +38 -0
- package/dist/oh-container.d.ts.map +1 -0
- package/dist/oh-container.js +116 -0
- package/dist/oh-container.js.map +1 -0
- package/dist/oh-drawer.d.ts +66 -0
- package/dist/oh-drawer.d.ts.map +1 -0
- package/dist/oh-drawer.js +284 -0
- package/dist/oh-drawer.js.map +1 -0
- package/dist/oh-footer.d.ts +40 -0
- package/dist/oh-footer.d.ts.map +1 -0
- package/dist/oh-footer.js +112 -0
- package/dist/oh-footer.js.map +1 -0
- package/dist/oh-grid.d.ts +40 -0
- package/dist/oh-grid.d.ts.map +1 -0
- package/dist/oh-grid.js +168 -0
- package/dist/oh-grid.js.map +1 -0
- package/dist/oh-hero.d.ts +28 -0
- package/dist/oh-hero.d.ts.map +1 -0
- package/dist/oh-hero.js +242 -0
- package/dist/oh-hero.js.map +1 -0
- package/dist/oh-icon.d.ts +44 -0
- package/dist/oh-icon.d.ts.map +1 -0
- package/dist/oh-icon.js +321 -0
- package/dist/oh-icon.js.map +1 -0
- package/dist/oh-input.d.ts +56 -0
- package/dist/oh-input.d.ts.map +1 -0
- package/dist/oh-input.figma.d.ts +2 -0
- package/dist/oh-input.figma.d.ts.map +1 -0
- package/dist/oh-input.figma.js +36 -0
- package/dist/oh-input.figma.js.map +1 -0
- package/dist/oh-input.js +320 -0
- package/dist/oh-input.js.map +1 -0
- package/dist/oh-link.d.ts +45 -0
- package/dist/oh-link.d.ts.map +1 -0
- package/dist/oh-link.js +392 -0
- package/dist/oh-link.js.map +1 -0
- package/dist/oh-modal.d.ts +54 -0
- package/dist/oh-modal.d.ts.map +1 -0
- package/dist/oh-modal.js +450 -0
- package/dist/oh-modal.js.map +1 -0
- package/dist/oh-navbar.d.ts +49 -0
- package/dist/oh-navbar.d.ts.map +1 -0
- package/dist/oh-navbar.js +185 -0
- package/dist/oh-navbar.js.map +1 -0
- package/dist/oh-progress.d.ts +56 -0
- package/dist/oh-progress.d.ts.map +1 -0
- package/dist/oh-progress.js +299 -0
- package/dist/oh-progress.js.map +1 -0
- package/dist/oh-radio-group.d.ts +43 -0
- package/dist/oh-radio-group.d.ts.map +1 -0
- package/dist/oh-radio-group.figma.d.ts +2 -0
- package/dist/oh-radio-group.figma.d.ts.map +1 -0
- package/dist/oh-radio-group.figma.js +22 -0
- package/dist/oh-radio-group.figma.js.map +1 -0
- package/dist/oh-radio-group.js +324 -0
- package/dist/oh-radio-group.js.map +1 -0
- package/dist/oh-radio.d.ts +50 -0
- package/dist/oh-radio.d.ts.map +1 -0
- package/dist/oh-radio.js +314 -0
- package/dist/oh-radio.js.map +1 -0
- package/dist/oh-select.d.ts +82 -0
- package/dist/oh-select.d.ts.map +1 -0
- package/dist/oh-select.js +638 -0
- package/dist/oh-select.js.map +1 -0
- package/dist/oh-skip-link.d.ts +37 -0
- package/dist/oh-skip-link.d.ts.map +1 -0
- package/dist/oh-skip-link.js +145 -0
- package/dist/oh-skip-link.js.map +1 -0
- package/dist/oh-stack.d.ts +36 -0
- package/dist/oh-stack.d.ts.map +1 -0
- package/dist/oh-stack.js +112 -0
- package/dist/oh-stack.js.map +1 -0
- package/dist/oh-tabs.d.ts +85 -0
- package/dist/oh-tabs.d.ts.map +1 -0
- package/dist/oh-tabs.js +417 -0
- package/dist/oh-tabs.js.map +1 -0
- package/dist/oh-toggle.d.ts +51 -0
- package/dist/oh-toggle.d.ts.map +1 -0
- package/dist/oh-toggle.js +219 -0
- package/dist/oh-toggle.js.map +1 -0
- package/dist/styles/typography.d.ts +15 -0
- package/dist/styles/typography.d.ts.map +1 -0
- package/dist/styles/typography.js +235 -0
- package/dist/styles/typography.js.map +1 -0
- package/package.json +140 -0
package/dist/oh-link.js
ADDED
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* oh-link
|
|
3
|
+
*
|
|
4
|
+
* A warm, playful link with retro-inspired styling.
|
|
5
|
+
* Two variants: inline (for body text) and standalone (for CTAs).
|
|
6
|
+
*
|
|
7
|
+
* DESIGN DECISIONS:
|
|
8
|
+
* ─────────────────
|
|
9
|
+
* 1. INLINE VARIANT
|
|
10
|
+
* - Dotted underline (quirky, retro feel)
|
|
11
|
+
* - Becomes solid on hover
|
|
12
|
+
* - Warm marmalade color
|
|
13
|
+
* - Subtle but distinctive
|
|
14
|
+
*
|
|
15
|
+
* 2. STANDALONE VARIANT
|
|
16
|
+
* - Bolder presence for CTAs
|
|
17
|
+
* - Offset shadow on hover (mini sticker effect)
|
|
18
|
+
* - Lift animation like other components
|
|
19
|
+
* - Arrow icon option
|
|
20
|
+
*
|
|
21
|
+
* 3. ACCESSIBILITY
|
|
22
|
+
* - Underline always visible (not color-only)
|
|
23
|
+
* - Clear focus state
|
|
24
|
+
* - Proper contrast ratios
|
|
25
|
+
*
|
|
26
|
+
* @element oh-link
|
|
27
|
+
*/
|
|
28
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
29
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
30
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
31
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
32
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
33
|
+
};
|
|
34
|
+
import { html, css, nothing } from "lit";
|
|
35
|
+
import { customElement, property } from "lit/decorators.js";
|
|
36
|
+
import { OhElement, baseStyles } from "./base.js";
|
|
37
|
+
let OhLink = class OhLink extends OhElement {
|
|
38
|
+
constructor() {
|
|
39
|
+
super(...arguments);
|
|
40
|
+
this.href = "";
|
|
41
|
+
this.target = "";
|
|
42
|
+
this.rel = "";
|
|
43
|
+
this.variant = "inline";
|
|
44
|
+
this.arrow = false;
|
|
45
|
+
this.inverse = false;
|
|
46
|
+
}
|
|
47
|
+
static { this.styles = [
|
|
48
|
+
baseStyles,
|
|
49
|
+
css `
|
|
50
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
51
|
+
ORANGE HALO LINK
|
|
52
|
+
Warm • Playful • Retro-inspired
|
|
53
|
+
═══════════════════════════════════════════════════════════════ */
|
|
54
|
+
|
|
55
|
+
:host {
|
|
56
|
+
display: inline;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.link {
|
|
60
|
+
font-family: var(--oh-font-family-sans);
|
|
61
|
+
color: var(--oh-color-brand-primary);
|
|
62
|
+
text-decoration: none;
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
position: relative;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
68
|
+
LINK TEXT WRAPPER
|
|
69
|
+
Uses pseudo-element for animated underline
|
|
70
|
+
═══════════════════════════════════════════════════════════════ */
|
|
71
|
+
|
|
72
|
+
.link__text {
|
|
73
|
+
position: relative;
|
|
74
|
+
text-decoration: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Dashed underline via pseudo-element (animatable) */
|
|
78
|
+
.link__text::after {
|
|
79
|
+
content: '';
|
|
80
|
+
position: absolute;
|
|
81
|
+
left: 0;
|
|
82
|
+
right: 0;
|
|
83
|
+
bottom: 0;
|
|
84
|
+
height: 2px;
|
|
85
|
+
background: repeating-linear-gradient(
|
|
86
|
+
to right,
|
|
87
|
+
var(--oh-color-brand-primary) 0,
|
|
88
|
+
var(--oh-color-brand-primary) 4px,
|
|
89
|
+
transparent 4px,
|
|
90
|
+
transparent 8px
|
|
91
|
+
);
|
|
92
|
+
transform-origin: right;
|
|
93
|
+
transform: scaleX(1);
|
|
94
|
+
transition: transform var(--oh-motion-slow) ease;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
98
|
+
INLINE VARIANT
|
|
99
|
+
Dashed underline shrinks right-to-left on hover
|
|
100
|
+
═══════════════════════════════════════════════════════════════ */
|
|
101
|
+
|
|
102
|
+
.link--inline {
|
|
103
|
+
display: inline-flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
text-decoration: none;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.link--inline:hover .link__text::after {
|
|
109
|
+
transform: scaleX(0);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.link--inline:active .link__text::after {
|
|
113
|
+
transform: scaleX(0);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Focus: solid underline + subtle background */
|
|
117
|
+
.link--inline:focus {
|
|
118
|
+
outline: 2px solid transparent;
|
|
119
|
+
outline-offset: 2px;
|
|
120
|
+
background-color: var(--oh-focus-glow-color);
|
|
121
|
+
border-radius: 2px;
|
|
122
|
+
padding: 0 2px;
|
|
123
|
+
margin: 0 -2px;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.link--inline:focus .link__text::after {
|
|
127
|
+
/* Solid underline on focus */
|
|
128
|
+
background: var(--oh-color-brand-primary);
|
|
129
|
+
height: 3px;
|
|
130
|
+
transform: scaleX(1);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Remove background for mouse users (click focus) */
|
|
134
|
+
.link--inline:focus:not(:focus-visible) {
|
|
135
|
+
background-color: transparent;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.link--inline:focus:not(:focus-visible) .link__text::after {
|
|
139
|
+
background: repeating-linear-gradient(
|
|
140
|
+
to right,
|
|
141
|
+
var(--oh-color-brand-primary) 0,
|
|
142
|
+
var(--oh-color-brand-primary) 4px,
|
|
143
|
+
transparent 4px,
|
|
144
|
+
transparent 8px
|
|
145
|
+
);
|
|
146
|
+
height: 2px;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
150
|
+
STANDALONE VARIANT
|
|
151
|
+
CTA-style with hover lift, dashed underline shrinks on hover
|
|
152
|
+
═══════════════════════════════════════════════════════════════ */
|
|
153
|
+
|
|
154
|
+
.link--standalone {
|
|
155
|
+
display: inline-flex;
|
|
156
|
+
align-items: center;
|
|
157
|
+
gap: var(--oh-spacing-2);
|
|
158
|
+
font-weight: var(--oh-font-weight-semibold);
|
|
159
|
+
font-size: var(--oh-font-size-lg);
|
|
160
|
+
text-decoration: none;
|
|
161
|
+
padding: var(--oh-spacing-1) 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.link--standalone:hover .link__text::after {
|
|
165
|
+
transform: scaleX(0);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.link--standalone:active .link__text::after {
|
|
169
|
+
transform: scaleX(0);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* Focus: solid underline + background */
|
|
173
|
+
.link--standalone:focus {
|
|
174
|
+
outline: 2px solid transparent;
|
|
175
|
+
outline-offset: 2px;
|
|
176
|
+
background-color: var(--oh-focus-glow-color);
|
|
177
|
+
border-radius: var(--oh-radius-xs);
|
|
178
|
+
padding: var(--oh-spacing-1) var(--oh-spacing-2);
|
|
179
|
+
margin: 0 calc(-1 * var(--oh-spacing-2));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.link--standalone:focus .link__text::after {
|
|
183
|
+
background: var(--oh-color-brand-primary);
|
|
184
|
+
height: 3px;
|
|
185
|
+
transform: scaleX(1);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* Remove background for mouse users (click focus) */
|
|
189
|
+
.link--standalone:focus:not(:focus-visible) {
|
|
190
|
+
background-color: transparent;
|
|
191
|
+
padding: var(--oh-spacing-1) 0;
|
|
192
|
+
margin: 0;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.link--standalone:focus:not(:focus-visible) .link__text::after {
|
|
196
|
+
background: repeating-linear-gradient(
|
|
197
|
+
to right,
|
|
198
|
+
var(--oh-color-brand-primary) 0,
|
|
199
|
+
var(--oh-color-brand-primary) 4px,
|
|
200
|
+
transparent 4px,
|
|
201
|
+
transparent 8px
|
|
202
|
+
);
|
|
203
|
+
height: 2px;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
207
|
+
ARROW ICON
|
|
208
|
+
Size matches line-height for visual balance
|
|
209
|
+
═══════════════════════════════════════════════════════════════ */
|
|
210
|
+
|
|
211
|
+
.link__arrow {
|
|
212
|
+
width: 1lh;
|
|
213
|
+
height: 1lh;
|
|
214
|
+
transition: transform var(--oh-motion-snappy) ease;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.link--standalone:hover .link__arrow {
|
|
218
|
+
transform: translateX(3px);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
222
|
+
EXTERNAL LINK ICON
|
|
223
|
+
Required for accessibility when opening new window
|
|
224
|
+
Size matches line-height for visual balance
|
|
225
|
+
═══════════════════════════════════════════════════════════════ */
|
|
226
|
+
|
|
227
|
+
.link__external {
|
|
228
|
+
width: 1em;
|
|
229
|
+
height: 1em;
|
|
230
|
+
margin-left: 0.25em;
|
|
231
|
+
flex-shrink: 0;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
235
|
+
VISUALLY HIDDEN (for screen readers)
|
|
236
|
+
═══════════════════════════════════════════════════════════════ */
|
|
237
|
+
|
|
238
|
+
.visually-hidden {
|
|
239
|
+
position: absolute;
|
|
240
|
+
width: 1px;
|
|
241
|
+
height: 1px;
|
|
242
|
+
padding: 0;
|
|
243
|
+
margin: -1px;
|
|
244
|
+
overflow: hidden;
|
|
245
|
+
clip: rect(0, 0, 0, 0);
|
|
246
|
+
white-space: nowrap;
|
|
247
|
+
border: 0;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
251
|
+
VISITED STATE
|
|
252
|
+
Same as default for consistent appearance
|
|
253
|
+
═══════════════════════════════════════════════════════════════ */
|
|
254
|
+
|
|
255
|
+
.link:visited {
|
|
256
|
+
color: var(--oh-color-brand-primary);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
260
|
+
INVERSE VARIANT (for colored backgrounds)
|
|
261
|
+
Contrasting text/underline for use on brand/accent surfaces
|
|
262
|
+
═══════════════════════════════════════════════════════════════ */
|
|
263
|
+
|
|
264
|
+
:host([inverse]) .link {
|
|
265
|
+
color: var(--oh-color-text-on-accent);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
:host([inverse]) .link:visited {
|
|
269
|
+
color: var(--oh-color-text-on-accent);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
:host([inverse]) .link__text::after {
|
|
273
|
+
background: repeating-linear-gradient(
|
|
274
|
+
to right,
|
|
275
|
+
var(--oh-color-text-on-accent) 0,
|
|
276
|
+
var(--oh-color-text-on-accent) 4px,
|
|
277
|
+
transparent 4px,
|
|
278
|
+
transparent 8px
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
:host([inverse]) .link--inline:focus {
|
|
283
|
+
background-color: rgba(0, 0, 0, 0.1);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
:host([inverse]) .link--inline:focus .link__text::after {
|
|
287
|
+
background: var(--oh-color-text-on-accent);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
:host([inverse]) .link--inline:focus:not(:focus-visible) {
|
|
291
|
+
background-color: transparent;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
:host([inverse]) .link--inline:focus:not(:focus-visible) .link__text::after {
|
|
295
|
+
background: repeating-linear-gradient(
|
|
296
|
+
to right,
|
|
297
|
+
var(--oh-color-text-on-accent) 0,
|
|
298
|
+
var(--oh-color-text-on-accent) 4px,
|
|
299
|
+
transparent 4px,
|
|
300
|
+
transparent 8px
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
:host([inverse]) .link--standalone:focus {
|
|
305
|
+
background-color: rgba(0, 0, 0, 0.1);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
:host([inverse]) .link--standalone:focus .link__text::after {
|
|
309
|
+
background: var(--oh-color-text-on-accent);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
:host([inverse]) .link--standalone:focus:not(:focus-visible) {
|
|
313
|
+
background-color: transparent;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
:host([inverse]) .link--standalone:focus:not(:focus-visible) .link__text::after {
|
|
317
|
+
background: repeating-linear-gradient(
|
|
318
|
+
to right,
|
|
319
|
+
var(--oh-color-text-on-accent) 0,
|
|
320
|
+
var(--oh-color-text-on-accent) 4px,
|
|
321
|
+
transparent 4px,
|
|
322
|
+
transparent 8px
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
327
|
+
REDUCED MOTION
|
|
328
|
+
═══════════════════════════════════════════════════════════════ */
|
|
329
|
+
|
|
330
|
+
@media (prefers-reduced-motion: reduce) {
|
|
331
|
+
.link,
|
|
332
|
+
.link__arrow,
|
|
333
|
+
.link__text::after {
|
|
334
|
+
transition-duration: 0.01ms !important;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
`,
|
|
338
|
+
]; }
|
|
339
|
+
render() {
|
|
340
|
+
const linkClasses = this.classMap({
|
|
341
|
+
link: true,
|
|
342
|
+
"link--inline": this.variant === "inline",
|
|
343
|
+
"link--standalone": this.variant === "standalone",
|
|
344
|
+
});
|
|
345
|
+
// Auto-add rel="noopener noreferrer" for external links
|
|
346
|
+
const computedRel = this.target === "_blank" && !this.rel
|
|
347
|
+
? "noopener noreferrer"
|
|
348
|
+
: this.rel;
|
|
349
|
+
const isExternal = this.target === "_blank";
|
|
350
|
+
return html `
|
|
351
|
+
<a
|
|
352
|
+
class=${linkClasses}
|
|
353
|
+
href=${this.href}
|
|
354
|
+
target=${this.target || nothing}
|
|
355
|
+
rel=${computedRel || nothing}
|
|
356
|
+
>
|
|
357
|
+
<span class="link__text"><slot></slot></span>${isExternal
|
|
358
|
+
? html `<svg class="link__external" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path fill-rule="evenodd" d="M4.25 5.5a.75.75 0 00-.75.75v8.5c0 .414.336.75.75.75h8.5a.75.75 0 00.75-.75v-4a.75.75 0 011.5 0v4A2.25 2.25 0 0112.75 17h-8.5A2.25 2.25 0 012 14.75v-8.5A2.25 2.25 0 014.25 4h5a.75.75 0 010 1.5h-5z" clip-rule="evenodd" /><path fill-rule="evenodd" d="M6.194 12.753a.75.75 0 001.06.053L16.5 4.44v2.81a.75.75 0 001.5 0v-4.5a.75.75 0 00-.75-.75h-4.5a.75.75 0 000 1.5h2.553l-9.056 8.194a.75.75 0 00-.053 1.06z" clip-rule="evenodd" /></svg><span class="visually-hidden">(opens in new tab)</span>`
|
|
359
|
+
: nothing}${this.variant === "standalone" && this.arrow && !isExternal
|
|
360
|
+
? html `
|
|
361
|
+
<svg class="link__arrow" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
362
|
+
<path fill-rule="evenodd" d="M3 10a.75.75 0 01.75-.75h10.638L10.23 5.29a.75.75 0 111.04-1.08l5.5 5.25a.75.75 0 010 1.08l-5.5 5.25a.75.75 0 11-1.04-1.08l4.158-3.96H3.75A.75.75 0 013 10z" clip-rule="evenodd" />
|
|
363
|
+
</svg>
|
|
364
|
+
`
|
|
365
|
+
: nothing}
|
|
366
|
+
</a>
|
|
367
|
+
`;
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
__decorate([
|
|
371
|
+
property({ type: String })
|
|
372
|
+
], OhLink.prototype, "href", void 0);
|
|
373
|
+
__decorate([
|
|
374
|
+
property({ type: String })
|
|
375
|
+
], OhLink.prototype, "target", void 0);
|
|
376
|
+
__decorate([
|
|
377
|
+
property({ type: String })
|
|
378
|
+
], OhLink.prototype, "rel", void 0);
|
|
379
|
+
__decorate([
|
|
380
|
+
property({ type: String })
|
|
381
|
+
], OhLink.prototype, "variant", void 0);
|
|
382
|
+
__decorate([
|
|
383
|
+
property({ type: Boolean })
|
|
384
|
+
], OhLink.prototype, "arrow", void 0);
|
|
385
|
+
__decorate([
|
|
386
|
+
property({ type: Boolean, reflect: true })
|
|
387
|
+
], OhLink.prototype, "inverse", void 0);
|
|
388
|
+
OhLink = __decorate([
|
|
389
|
+
customElement("oh-link")
|
|
390
|
+
], OhLink);
|
|
391
|
+
export { OhLink };
|
|
392
|
+
//# sourceMappingURL=oh-link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oh-link.js","sourceRoot":"","sources":["../src/oh-link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;;;;;;;AAEH,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAK3C,IAAM,MAAM,GAAZ,MAAM,MAAO,SAAQ,SAAS;IAA9B;;QAuSL,SAAI,GAAG,EAAE,CAAC;QAGV,WAAM,GAAG,EAAE,CAAC;QAGZ,QAAG,GAAG,EAAE,CAAC;QAGT,YAAO,GAAgB,QAAQ,CAAC;QAGhC,UAAK,GAAG,KAAK,CAAC;QAGd,YAAO,GAAG,KAAK,CAAC;IAmClB,CAAC;aAxViB,WAAM,GAAG;QACvB,UAAU;QACV,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAgSF;KACF,AAnSqB,CAmSpB;IAoBF,MAAM;QACJ,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC;YAChC,IAAI,EAAE,IAAI;YACV,cAAc,EAAE,IAAI,CAAC,OAAO,KAAK,QAAQ;YACzC,kBAAkB,EAAE,IAAI,CAAC,OAAO,KAAK,YAAY;SAClD,CAAC,CAAC;QAEH,wDAAwD;QACxD,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,GAAG;YACvD,CAAC,CAAC,qBAAqB;YACvB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAEb,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC;QAE5C,OAAO,IAAI,CAAA;;gBAEC,WAAW;eACZ,IAAI,CAAC,IAAI;iBACP,IAAI,CAAC,MAAM,IAAI,OAAO;cACzB,WAAW,IAAI,OAAO;;uDAEmB,UAAU;YACvD,CAAC,CAAC,IAAI,CAAA,8lBAA8lB;YACpmB,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,KAAK,YAAY,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,UAAU;YACtE,CAAC,CAAC,IAAI,CAAA;;;;aAIH;YACH,CAAC,CAAC,OAAO;;KAEd,CAAC;IACJ,CAAC;;AAjDD;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;oCACjB;AAGV;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;sCACf;AAGZ;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;mCAClB;AAGT;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;uCACK;AAGhC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;qCACd;AAGd;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;uCAC3B;AAtTL,MAAM;IADlB,aAAa,CAAC,SAAS,CAAC;GACZ,MAAM,CAyVlB"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* oh-modal
|
|
3
|
+
*
|
|
4
|
+
* A chunky, accessible modal dialog with focus trapping.
|
|
5
|
+
*
|
|
6
|
+
* DESIGN DECISIONS:
|
|
7
|
+
* ─────────────────
|
|
8
|
+
* 1. CHUNKY & LIFTED
|
|
9
|
+
* - 2.5px border like other components
|
|
10
|
+
* - Offset shadow (4px 4px) — feels like a lifted surface
|
|
11
|
+
* - Warm backdrop, not pure black
|
|
12
|
+
*
|
|
13
|
+
* 2. ACCESSIBLE
|
|
14
|
+
* - Focus trap when open
|
|
15
|
+
* - Escape key closes (when dismissible)
|
|
16
|
+
* - Focus returns to trigger on close
|
|
17
|
+
* - role="dialog" + aria-modal="true"
|
|
18
|
+
*
|
|
19
|
+
* 3. FLEXIBLE STRUCTURE
|
|
20
|
+
* - Optional heading
|
|
21
|
+
* - Scrollable body content
|
|
22
|
+
* - Optional footer slot for actions
|
|
23
|
+
*
|
|
24
|
+
* @element oh-modal
|
|
25
|
+
*/
|
|
26
|
+
import { OhElement } from "./base.js";
|
|
27
|
+
export type ModalSize = "sm" | "md" | "lg";
|
|
28
|
+
export declare class OhModal extends OhElement {
|
|
29
|
+
static styles: import("lit").CSSResult[];
|
|
30
|
+
open: boolean;
|
|
31
|
+
heading: string;
|
|
32
|
+
dismissible: boolean;
|
|
33
|
+
size: ModalSize;
|
|
34
|
+
private _previousActiveElement;
|
|
35
|
+
private _closeButton;
|
|
36
|
+
connectedCallback(): void;
|
|
37
|
+
updated(changedProperties: Map<string, unknown>): void;
|
|
38
|
+
private _onOpen;
|
|
39
|
+
private _onClose;
|
|
40
|
+
private _handleKeyDown;
|
|
41
|
+
private _trapFocus;
|
|
42
|
+
private _getFocusableElements;
|
|
43
|
+
private _focusFirstElement;
|
|
44
|
+
private _handleBackdropClick;
|
|
45
|
+
private _requestClose;
|
|
46
|
+
disconnectedCallback(): void;
|
|
47
|
+
render(): import("lit").TemplateResult<1>;
|
|
48
|
+
}
|
|
49
|
+
declare global {
|
|
50
|
+
interface HTMLElementTagNameMap {
|
|
51
|
+
"oh-modal": OhModal;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=oh-modal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oh-modal.d.ts","sourceRoot":"","sources":["../src/oh-modal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,EAAE,SAAS,EAAc,MAAM,WAAW,CAAC;AAElD,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE3C,qBACa,OAAQ,SAAQ,SAAS;IACpC,OAAgB,MAAM,4BA0NpB;IAGF,IAAI,UAAS;IAGb,OAAO,SAAM;IAGb,WAAW,UAAQ;IAGnB,IAAI,EAAE,SAAS,CAAQ;IAGvB,OAAO,CAAC,sBAAsB,CAA4B;IAI1D,OAAO,CAAC,YAAY,CAAqB;IAEzC,iBAAiB;IAKjB,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAU/C,OAAO,CAAC,OAAO;IAoBf,OAAO,CAAC,QAAQ;IAchB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,UAAU;IAsBlB,OAAO,CAAC,qBAAqB;IAqB7B,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,aAAa;IAKrB,oBAAoB;IAMpB,MAAM;CA8DP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,OAAO,CAAC;KACrB;CACF"}
|