@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
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* oh-input
|
|
3
|
+
*
|
|
4
|
+
* A chunky, inset input field that feels pressed into the page.
|
|
5
|
+
* On focus, it rises to meet you.
|
|
6
|
+
*
|
|
7
|
+
* DESIGN DECISIONS:
|
|
8
|
+
* ─────────────────
|
|
9
|
+
* 1. CHUNKY & CONFIDENT
|
|
10
|
+
* - Thick border (2.5px) that feels illustrative
|
|
11
|
+
* - Solid fill, no subtle gradients
|
|
12
|
+
* - 10px rounded corners (matches button)
|
|
13
|
+
*
|
|
14
|
+
* 2. INSET SHADOW (PRESSED IN)
|
|
15
|
+
* - Shadow offset to top-left (inset)
|
|
16
|
+
* - Feels pressed into the surface
|
|
17
|
+
* - Opposite of button's outset sticker effect
|
|
18
|
+
*
|
|
19
|
+
* 3. FOCUS RISES UP
|
|
20
|
+
* - Inset shadow disappears
|
|
21
|
+
* - Outset shadow appears (field lifts)
|
|
22
|
+
* - Border turns marmalade
|
|
23
|
+
* - Clear visual hierarchy
|
|
24
|
+
*
|
|
25
|
+
* @element oh-input
|
|
26
|
+
*/
|
|
27
|
+
import { OhElement } from "./base.js";
|
|
28
|
+
export type InputType = "text" | "email" | "password" | "search" | "tel" | "url";
|
|
29
|
+
export type InputState = "default" | "hover" | "focus";
|
|
30
|
+
export declare class OhInput extends OhElement {
|
|
31
|
+
static styles: import("lit").CSSResult[];
|
|
32
|
+
type: InputType;
|
|
33
|
+
value: string;
|
|
34
|
+
placeholder: string;
|
|
35
|
+
label: string;
|
|
36
|
+
helperText: string;
|
|
37
|
+
errorText: string;
|
|
38
|
+
required: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Force a visual state (for documentation/Figma sync only)
|
|
41
|
+
* Values: 'hover' | 'focus'
|
|
42
|
+
*/
|
|
43
|
+
forceState: InputState;
|
|
44
|
+
private _input;
|
|
45
|
+
private _handleInput;
|
|
46
|
+
private _handleChange;
|
|
47
|
+
focus(): void;
|
|
48
|
+
blur(): void;
|
|
49
|
+
render(): import("lit").TemplateResult<1>;
|
|
50
|
+
}
|
|
51
|
+
declare global {
|
|
52
|
+
interface HTMLElementTagNameMap {
|
|
53
|
+
"oh-input": OhInput;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=oh-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oh-input.d.ts","sourceRoot":"","sources":["../src/oh-input.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,EAAE,SAAS,EAAc,MAAM,WAAW,CAAC;AAElD,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC;AACjF,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAEvD,qBACa,OAAQ,SAAQ,SAAS;IACpC,OAAgB,MAAM,4BAoKpB;IAGF,IAAI,EAAE,SAAS,CAAU;IAGzB,KAAK,SAAM;IAGX,WAAW,SAAM;IAGjB,KAAK,SAAM;IAGX,UAAU,SAAM;IAGhB,SAAS,SAAM;IAGf,QAAQ,UAAS;IAEjB;;;OAGG;IAEH,UAAU,EAAE,UAAU,CAAa;IAGnC,OAAO,CAAC,MAAM,CAAoB;IAElC,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,aAAa;IAIrB,KAAK;IAIL,IAAI;IAIJ,MAAM;CA2DP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,OAAO,CAAC;KACrB;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oh-input.figma.d.ts","sourceRoot":"","sources":["../src/oh-input.figma.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import figma, { html } from "@figma/code-connect/html";
|
|
2
|
+
/**
|
|
3
|
+
* Code Connect for oh-input
|
|
4
|
+
*
|
|
5
|
+
* Figma Properties:
|
|
6
|
+
* - Label (text): Field label
|
|
7
|
+
* - Value (text): Input content
|
|
8
|
+
* - Show Placeholder (boolean): Whether to show placeholder
|
|
9
|
+
* - Placeholder (text): Placeholder text when empty
|
|
10
|
+
* - Helper Text (text): Help text below input
|
|
11
|
+
* - Error Text (text): Error message (triggers error styling when set)
|
|
12
|
+
* - Required (boolean): Shows asterisk on label
|
|
13
|
+
* - State (variant): Default, Hover, Focus
|
|
14
|
+
*/
|
|
15
|
+
figma.connect("https://www.figma.com/design/q9ZYrOj2w9DrTVmgQFU7bu/OHDS?node-id=1-40", {
|
|
16
|
+
props: {
|
|
17
|
+
label: figma.string("Label"),
|
|
18
|
+
value: figma.string("Value"),
|
|
19
|
+
showPlaceholder: figma.boolean("Show Placeholder"),
|
|
20
|
+
placeholder: figma.string("Placeholder"),
|
|
21
|
+
required: figma.boolean("Required"),
|
|
22
|
+
helperText: figma.string("Helper Text"),
|
|
23
|
+
errorText: figma.string("Error Text"),
|
|
24
|
+
},
|
|
25
|
+
example: (props) => html `
|
|
26
|
+
<oh-input
|
|
27
|
+
label="${props.label}"
|
|
28
|
+
value="${props.value}"
|
|
29
|
+
placeholder="${props.showPlaceholder ? props.placeholder : ""}"
|
|
30
|
+
?required="${props.required}"
|
|
31
|
+
helper-text="${props.helperText}"
|
|
32
|
+
error-text="${props.errorText}"
|
|
33
|
+
></oh-input>
|
|
34
|
+
`,
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=oh-input.figma.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oh-input.figma.js","sourceRoot":"","sources":["../src/oh-input.figma.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAEvD;;;;;;;;;;;;GAYG;AAEH,KAAK,CAAC,OAAO,CACX,uEAAuE,EACvE;IACE,KAAK,EAAE;QACL,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;QAC5B,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;QAC5B,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC;QAClD,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC;QACxC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;QACnC,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC;QACvC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC;KACtC;IACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAA;;iBAEX,KAAK,CAAC,KAAK;iBACX,KAAK,CAAC,KAAK;uBACL,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;qBAChD,KAAK,CAAC,QAAQ;uBACZ,KAAK,CAAC,UAAU;sBACjB,KAAK,CAAC,SAAS;;KAEhC;CACF,CACF,CAAC"}
|
package/dist/oh-input.js
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* oh-input
|
|
3
|
+
*
|
|
4
|
+
* A chunky, inset input field that feels pressed into the page.
|
|
5
|
+
* On focus, it rises to meet you.
|
|
6
|
+
*
|
|
7
|
+
* DESIGN DECISIONS:
|
|
8
|
+
* ─────────────────
|
|
9
|
+
* 1. CHUNKY & CONFIDENT
|
|
10
|
+
* - Thick border (2.5px) that feels illustrative
|
|
11
|
+
* - Solid fill, no subtle gradients
|
|
12
|
+
* - 10px rounded corners (matches button)
|
|
13
|
+
*
|
|
14
|
+
* 2. INSET SHADOW (PRESSED IN)
|
|
15
|
+
* - Shadow offset to top-left (inset)
|
|
16
|
+
* - Feels pressed into the surface
|
|
17
|
+
* - Opposite of button's outset sticker effect
|
|
18
|
+
*
|
|
19
|
+
* 3. FOCUS RISES UP
|
|
20
|
+
* - Inset shadow disappears
|
|
21
|
+
* - Outset shadow appears (field lifts)
|
|
22
|
+
* - Border turns marmalade
|
|
23
|
+
* - Clear visual hierarchy
|
|
24
|
+
*
|
|
25
|
+
* @element oh-input
|
|
26
|
+
*/
|
|
27
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
28
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
29
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
30
|
+
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;
|
|
31
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
32
|
+
};
|
|
33
|
+
import { html, css, nothing } from "lit";
|
|
34
|
+
import { customElement, property, query } from "lit/decorators.js";
|
|
35
|
+
import { OhElement, baseStyles } from "./base.js";
|
|
36
|
+
let OhInput = class OhInput extends OhElement {
|
|
37
|
+
constructor() {
|
|
38
|
+
super(...arguments);
|
|
39
|
+
this.type = "text";
|
|
40
|
+
this.value = "";
|
|
41
|
+
this.placeholder = "";
|
|
42
|
+
this.label = "";
|
|
43
|
+
this.helperText = "";
|
|
44
|
+
this.errorText = "";
|
|
45
|
+
this.required = false;
|
|
46
|
+
/**
|
|
47
|
+
* Force a visual state (for documentation/Figma sync only)
|
|
48
|
+
* Values: 'hover' | 'focus'
|
|
49
|
+
*/
|
|
50
|
+
this.forceState = "default";
|
|
51
|
+
}
|
|
52
|
+
static { this.styles = [
|
|
53
|
+
baseStyles,
|
|
54
|
+
css `
|
|
55
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
56
|
+
ORANGE HALO INPUT
|
|
57
|
+
Chunky • Inset • Rises on Focus
|
|
58
|
+
═══════════════════════════════════════════════════════════════ */
|
|
59
|
+
|
|
60
|
+
:host {
|
|
61
|
+
display: block;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.input-wrapper {
|
|
65
|
+
display: flex;
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
gap: var(--oh-spacing-2);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* ─── Label: friendly and readable (16px minimum) ─── */
|
|
71
|
+
.label {
|
|
72
|
+
font-family: var(--oh-font-family-sans);
|
|
73
|
+
font-size: var(--oh-font-size-base);
|
|
74
|
+
font-weight: var(--oh-font-weight-semibold);
|
|
75
|
+
color: var(--oh-color-text-primary);
|
|
76
|
+
letter-spacing: var(--oh-font-letter-spacing-wide);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.label--required::after {
|
|
80
|
+
content: " *";
|
|
81
|
+
color: var(--oh-color-feedback-error);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
85
|
+
INPUT FIELD
|
|
86
|
+
Thick border, inset shadow, solid fill
|
|
87
|
+
═══════════════════════════════════════════════════════════════ */
|
|
88
|
+
|
|
89
|
+
.input {
|
|
90
|
+
width: 100%;
|
|
91
|
+
font-family: var(--oh-font-family-sans);
|
|
92
|
+
color: var(--oh-color-text-primary);
|
|
93
|
+
|
|
94
|
+
/* Solid fill — no gradients */
|
|
95
|
+
background-color: var(--oh-color-surface-base);
|
|
96
|
+
|
|
97
|
+
/* Thick illustrative border (WCAG 3:1 compliant) */
|
|
98
|
+
border: var(--oh-input-base-border-width) solid var(--oh-color-border-emphasis);
|
|
99
|
+
border-radius: var(--oh-radius-md);
|
|
100
|
+
|
|
101
|
+
/* Inset offset shadow: pressed into page */
|
|
102
|
+
box-shadow: var(--oh-shadow-chunky-inset, inset 3px 3px 0 0 rgba(61, 50, 41, 0.15));
|
|
103
|
+
|
|
104
|
+
transition:
|
|
105
|
+
border-color var(--oh-motion-snappy) ease,
|
|
106
|
+
box-shadow var(--oh-motion-snappy) ease,
|
|
107
|
+
background-color var(--oh-motion-quick) ease;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.input::placeholder {
|
|
111
|
+
color: var(--oh-color-text-secondary); /* Readable placeholder */
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* ─── Hover: border warms up ─── */
|
|
115
|
+
.input:hover:not(:focus) {
|
|
116
|
+
border-color: var(--oh-color-border-hover);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* ─── Focus: even inner ring on all sides (no layout shift) ─── */
|
|
120
|
+
.input:focus {
|
|
121
|
+
outline: none;
|
|
122
|
+
background-color: var(--oh-color-surface-white);
|
|
123
|
+
border-color: var(--oh-color-border-focus);
|
|
124
|
+
|
|
125
|
+
/* 2px inset ring + 2.5px border = ~4.5px total, even on all sides */
|
|
126
|
+
box-shadow: inset 0 0 0 2px var(--oh-color-border-focus);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
130
|
+
SIZE (single size for consistency)
|
|
131
|
+
═══════════════════════════════════════════════════════════════ */
|
|
132
|
+
|
|
133
|
+
.input {
|
|
134
|
+
font-size: var(--oh-font-size-lg);
|
|
135
|
+
padding: var(--oh-spacing-3) var(--oh-spacing-4);
|
|
136
|
+
min-height: var(--oh-input-size-md-min-height);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
140
|
+
ERROR STATE
|
|
141
|
+
Warm red, chunky — still follows the same language
|
|
142
|
+
═══════════════════════════════════════════════════════════════ */
|
|
143
|
+
|
|
144
|
+
.input--error {
|
|
145
|
+
border-color: var(--oh-color-feedback-error);
|
|
146
|
+
background-color: var(--oh-color-feedback-error-subtle);
|
|
147
|
+
box-shadow: inset 3px 3px 0 0 var(--oh-shadow-error);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.input--error:focus {
|
|
151
|
+
border-color: var(--oh-color-feedback-error);
|
|
152
|
+
box-shadow: inset 0 0 0 2px var(--oh-color-feedback-error);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
156
|
+
HELPER TEXT
|
|
157
|
+
═══════════════════════════════════════════════════════════════ */
|
|
158
|
+
|
|
159
|
+
.helper {
|
|
160
|
+
font-family: var(--oh-font-family-sans);
|
|
161
|
+
font-size: var(--oh-font-size-base);
|
|
162
|
+
color: var(--oh-color-text-secondary);
|
|
163
|
+
letter-spacing: var(--oh-font-letter-spacing-wide);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.helper--error {
|
|
167
|
+
display: flex;
|
|
168
|
+
align-items: center;
|
|
169
|
+
gap: var(--oh-spacing-2);
|
|
170
|
+
color: var(--oh-color-feedback-error);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.error-icon {
|
|
174
|
+
flex-shrink: 0;
|
|
175
|
+
width: var(--oh-spacing-4);
|
|
176
|
+
height: var(--oh-spacing-4);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
180
|
+
REDUCED MOTION
|
|
181
|
+
═══════════════════════════════════════════════════════════════ */
|
|
182
|
+
|
|
183
|
+
@media (prefers-reduced-motion: reduce) {
|
|
184
|
+
.input {
|
|
185
|
+
transition-duration: 0.01ms !important;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
190
|
+
FORCED STATES (for Figma Sync / documentation)
|
|
191
|
+
═══════════════════════════════════════════════════════════════ */
|
|
192
|
+
|
|
193
|
+
/* Forced Hover */
|
|
194
|
+
:host([force-state="hover"]) .input {
|
|
195
|
+
border-color: var(--oh-color-border-hover);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Forced Focus */
|
|
199
|
+
:host([force-state="focus"]) .input {
|
|
200
|
+
background-color: var(--oh-color-surface-white);
|
|
201
|
+
border-color: var(--oh-color-border-focus);
|
|
202
|
+
box-shadow: inset 0 0 0 2px var(--oh-color-border-focus);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* Error + Forced Hover */
|
|
206
|
+
:host([force-state="hover"]) .input--error {
|
|
207
|
+
border-color: var(--oh-color-feedback-error-hover, #b83a00);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/* Error + Forced Focus */
|
|
211
|
+
:host([force-state="focus"]) .input--error {
|
|
212
|
+
border-color: var(--oh-color-feedback-error);
|
|
213
|
+
box-shadow: inset 0 0 0 2px var(--oh-color-feedback-error);
|
|
214
|
+
}
|
|
215
|
+
`,
|
|
216
|
+
]; }
|
|
217
|
+
_handleInput(event) {
|
|
218
|
+
const target = event.target;
|
|
219
|
+
this.value = target.value;
|
|
220
|
+
this.emit("oh-input", { value: this.value, originalEvent: event });
|
|
221
|
+
}
|
|
222
|
+
_handleChange(event) {
|
|
223
|
+
this.emit("oh-change", { value: this.value, originalEvent: event });
|
|
224
|
+
}
|
|
225
|
+
focus() {
|
|
226
|
+
this._input?.focus();
|
|
227
|
+
}
|
|
228
|
+
blur() {
|
|
229
|
+
this._input?.blur();
|
|
230
|
+
}
|
|
231
|
+
render() {
|
|
232
|
+
const hasError = !!this.errorText;
|
|
233
|
+
const helperContent = hasError ? this.errorText : this.helperText;
|
|
234
|
+
const inputClasses = this.classMap({
|
|
235
|
+
input: true,
|
|
236
|
+
"input--error": hasError,
|
|
237
|
+
});
|
|
238
|
+
return html `
|
|
239
|
+
<div class="input-wrapper">
|
|
240
|
+
${this.label
|
|
241
|
+
? html `
|
|
242
|
+
<label
|
|
243
|
+
class="label ${this.required ? "label--required" : ""}"
|
|
244
|
+
part="label"
|
|
245
|
+
for="input"
|
|
246
|
+
>
|
|
247
|
+
${this.label}
|
|
248
|
+
</label>
|
|
249
|
+
`
|
|
250
|
+
: nothing}
|
|
251
|
+
|
|
252
|
+
<input
|
|
253
|
+
id="input"
|
|
254
|
+
part="input"
|
|
255
|
+
class=${inputClasses}
|
|
256
|
+
type=${this.type}
|
|
257
|
+
.value=${this.value}
|
|
258
|
+
placeholder=${this.placeholder || nothing}
|
|
259
|
+
?required=${this.required}
|
|
260
|
+
aria-invalid=${hasError ? "true" : nothing}
|
|
261
|
+
aria-describedby=${helperContent ? "helper" : nothing}
|
|
262
|
+
@input=${this._handleInput}
|
|
263
|
+
@change=${this._handleChange}
|
|
264
|
+
/>
|
|
265
|
+
|
|
266
|
+
${helperContent
|
|
267
|
+
? html `
|
|
268
|
+
<span
|
|
269
|
+
id="helper"
|
|
270
|
+
class="helper ${hasError ? "helper--error" : ""}"
|
|
271
|
+
part="helper"
|
|
272
|
+
role=${hasError ? "alert" : nothing}
|
|
273
|
+
>
|
|
274
|
+
${hasError
|
|
275
|
+
? html `
|
|
276
|
+
<svg class="error-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
277
|
+
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
|
|
278
|
+
</svg>
|
|
279
|
+
`
|
|
280
|
+
: nothing}
|
|
281
|
+
${helperContent}
|
|
282
|
+
</span>
|
|
283
|
+
`
|
|
284
|
+
: nothing}
|
|
285
|
+
</div>
|
|
286
|
+
`;
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
__decorate([
|
|
290
|
+
property({ type: String })
|
|
291
|
+
], OhInput.prototype, "type", void 0);
|
|
292
|
+
__decorate([
|
|
293
|
+
property({ type: String })
|
|
294
|
+
], OhInput.prototype, "value", void 0);
|
|
295
|
+
__decorate([
|
|
296
|
+
property({ type: String })
|
|
297
|
+
], OhInput.prototype, "placeholder", void 0);
|
|
298
|
+
__decorate([
|
|
299
|
+
property({ type: String })
|
|
300
|
+
], OhInput.prototype, "label", void 0);
|
|
301
|
+
__decorate([
|
|
302
|
+
property({ type: String })
|
|
303
|
+
], OhInput.prototype, "helperText", void 0);
|
|
304
|
+
__decorate([
|
|
305
|
+
property({ type: String })
|
|
306
|
+
], OhInput.prototype, "errorText", void 0);
|
|
307
|
+
__decorate([
|
|
308
|
+
property({ type: Boolean, reflect: true })
|
|
309
|
+
], OhInput.prototype, "required", void 0);
|
|
310
|
+
__decorate([
|
|
311
|
+
property({ type: String, reflect: true, attribute: "force-state" })
|
|
312
|
+
], OhInput.prototype, "forceState", void 0);
|
|
313
|
+
__decorate([
|
|
314
|
+
query("input")
|
|
315
|
+
], OhInput.prototype, "_input", void 0);
|
|
316
|
+
OhInput = __decorate([
|
|
317
|
+
customElement("oh-input")
|
|
318
|
+
], OhInput);
|
|
319
|
+
export { OhInput };
|
|
320
|
+
//# sourceMappingURL=oh-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oh-input.js","sourceRoot":"","sources":["../src/oh-input.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
import { OhElement } from "./base.js";
|
|
29
|
+
export type LinkVariant = "inline" | "standalone";
|
|
30
|
+
export declare class OhLink extends OhElement {
|
|
31
|
+
static styles: import("lit").CSSResult[];
|
|
32
|
+
href: string;
|
|
33
|
+
target: string;
|
|
34
|
+
rel: string;
|
|
35
|
+
variant: LinkVariant;
|
|
36
|
+
arrow: boolean;
|
|
37
|
+
inverse: boolean;
|
|
38
|
+
render(): import("lit").TemplateResult<1>;
|
|
39
|
+
}
|
|
40
|
+
declare global {
|
|
41
|
+
interface HTMLElementTagNameMap {
|
|
42
|
+
"oh-link": OhLink;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=oh-link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oh-link.d.ts","sourceRoot":"","sources":["../src/oh-link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,EAAE,SAAS,EAAc,MAAM,WAAW,CAAC;AAElD,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,YAAY,CAAC;AAElD,qBACa,MAAO,SAAQ,SAAS;IACnC,OAAgB,MAAM,4BAmSpB;IAGF,IAAI,SAAM;IAGV,MAAM,SAAM;IAGZ,GAAG,SAAM;IAGT,OAAO,EAAE,WAAW,CAAY;IAGhC,KAAK,UAAS;IAGd,OAAO,UAAS;IAEhB,MAAM;CAiCP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,SAAS,EAAE,MAAM,CAAC;KACnB;CACF"}
|