elvish-css 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/LICENSE +21 -0
- package/README.md +518 -0
- package/dist/elvish.css +2194 -0
- package/dist/elvish.d.ts +78 -0
- package/dist/elvish.esm.js +2185 -0
- package/dist/elvish.iife.js +2169 -0
- package/dist/elvish.min.css +9 -0
- package/dist/elvish.umd.js +2173 -0
- package/elvish.css +28 -0
- package/elvish.js +81 -0
- package/global/global.css +16 -0
- package/global/modern.css +305 -0
- package/global/reset.css +507 -0
- package/global/tokens.css +154 -0
- package/global/transitions.css +288 -0
- package/global/transitions.js +289 -0
- package/global/utilities.css +151 -0
- package/package.json +61 -0
- package/primitives/adleithian/adleithian.css +16 -0
- package/primitives/adleithian/adleithian.js +63 -0
- package/primitives/bau/bau.css +86 -0
- package/primitives/bau/bau.js +127 -0
- package/primitives/enedh/enedh.css +38 -0
- package/primitives/enedh/enedh.js +110 -0
- package/primitives/esgal/esgal.css +39 -0
- package/primitives/esgal/esgal.js +115 -0
- package/primitives/fano/fano.css +28 -0
- package/primitives/fano/fano.js +108 -0
- package/primitives/gant-thala/gant-thala.css +32 -0
- package/primitives/gant-thala/gant-thala.js +69 -0
- package/primitives/glan-tholl/glan-tholl.css +71 -0
- package/primitives/glan-tholl/glan-tholl.js +147 -0
- package/primitives/glan-veleg/glan-veleg.css +45 -0
- package/primitives/glan-veleg/glan-veleg.js +138 -0
- package/primitives/gonath/gonath.css +57 -0
- package/primitives/gonath/gonath.js +113 -0
- package/primitives/gwistindor/gwistindor.css +52 -0
- package/primitives/gwistindor/gwistindor.js +96 -0
- package/primitives/hath/hath.css +39 -0
- package/primitives/hath/hath.js +107 -0
- package/primitives/him/him.css +43 -0
- package/primitives/him/him.js +169 -0
- package/primitives/miriant/miriant.css +75 -0
- package/primitives/miriant/miriant.js +158 -0
- package/primitives/thann/thann.css +57 -0
- package/primitives/thann/thann.js +96 -0
- package/primitives/tiniath/tiniath.css +16 -0
- package/primitives/tiniath/tiniath.js +88 -0
- package/primitives/vircantie/vircantie.css +24 -0
- package/primitives/vircantie/vircantie.js +83 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Elvish - Utilities
|
|
3
|
+
*
|
|
4
|
+
* Final adjustments. Use sparingly.
|
|
5
|
+
* Naming convention: property\:value
|
|
6
|
+
*
|
|
7
|
+
* !important is intentional - utilities are for overrides.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/* ===== TEXT ALIGNMENT ===== */
|
|
11
|
+
.text-align\:start { text-align: start !important; }
|
|
12
|
+
.text-align\:center { text-align: center !important; }
|
|
13
|
+
.text-align\:end { text-align: end !important; }
|
|
14
|
+
|
|
15
|
+
/* ===== FONT SIZES ===== */
|
|
16
|
+
.font-size\:s-2 { font-size: var(--s-2) !important; }
|
|
17
|
+
.font-size\:s-1 { font-size: var(--s-1) !important; }
|
|
18
|
+
.font-size\:s0 { font-size: var(--s0) !important; }
|
|
19
|
+
.font-size\:s1 { font-size: var(--s1) !important; }
|
|
20
|
+
.font-size\:s2 { font-size: var(--s2) !important; }
|
|
21
|
+
.font-size\:s3 { font-size: var(--s3) !important; }
|
|
22
|
+
.font-size\:s4 { font-size: var(--s4) !important; }
|
|
23
|
+
|
|
24
|
+
/* ===== FONT WEIGHT ===== */
|
|
25
|
+
.font-weight\:normal { font-weight: normal !important; }
|
|
26
|
+
.font-weight\:bold { font-weight: bold !important; }
|
|
27
|
+
|
|
28
|
+
/* ===== COLORS ===== */
|
|
29
|
+
.color\:dark { color: var(--color-dark) !important; }
|
|
30
|
+
.color\:light { color: var(--color-light) !important; }
|
|
31
|
+
.color\:accent { color: var(--color-accent) !important; }
|
|
32
|
+
|
|
33
|
+
.bg\:dark { background-color: var(--color-dark) !important; }
|
|
34
|
+
.bg\:light { background-color: var(--color-light) !important; }
|
|
35
|
+
.bg\:accent { background-color: var(--color-accent) !important; }
|
|
36
|
+
|
|
37
|
+
/* ===== MEASURE ===== */
|
|
38
|
+
.max-inline-size\:measure { max-inline-size: var(--measure) !important; }
|
|
39
|
+
.max-inline-size\:measure\/2 { max-inline-size: calc(var(--measure) / 2) !important; }
|
|
40
|
+
.max-inline-size\:measure\/3 { max-inline-size: calc(var(--measure) / 3) !important; }
|
|
41
|
+
.max-inline-size\:none { max-inline-size: none !important; }
|
|
42
|
+
|
|
43
|
+
/* ===== WIDTH ===== */
|
|
44
|
+
.inline-size\:100 { inline-size: 100% !important; }
|
|
45
|
+
.inline-size\:auto { inline-size: auto !important; }
|
|
46
|
+
|
|
47
|
+
/* ===== HEIGHT ===== */
|
|
48
|
+
.block-size\:100 { block-size: 100% !important; }
|
|
49
|
+
.block-size\:100vh { block-size: 100vh !important; }
|
|
50
|
+
.block-size\:auto { block-size: auto !important; }
|
|
51
|
+
|
|
52
|
+
/* ===== MARGIN ===== */
|
|
53
|
+
.margin\:0 { margin: 0 !important; }
|
|
54
|
+
.margin-block\:0 { margin-block: 0 !important; }
|
|
55
|
+
.margin-inline\:0 { margin-inline: 0 !important; }
|
|
56
|
+
.margin-inline\:auto { margin-inline: auto !important; }
|
|
57
|
+
|
|
58
|
+
/* ===== PADDING ===== */
|
|
59
|
+
.padding\:s-1 { padding: var(--s-1) !important; }
|
|
60
|
+
.padding\:s0 { padding: var(--s0) !important; }
|
|
61
|
+
.padding\:s1 { padding: var(--s1) !important; }
|
|
62
|
+
.padding\:s2 { padding: var(--s2) !important; }
|
|
63
|
+
|
|
64
|
+
/* ===== GAP ===== */
|
|
65
|
+
.gap\:s-1 { gap: var(--s-1) !important; }
|
|
66
|
+
.gap\:s0 { gap: var(--s0) !important; }
|
|
67
|
+
.gap\:s1 { gap: var(--s1) !important; }
|
|
68
|
+
.gap\:s2 { gap: var(--s2) !important; }
|
|
69
|
+
|
|
70
|
+
/* ===== FLEX ===== */
|
|
71
|
+
.flex-grow\:1 { flex-grow: 1 !important; }
|
|
72
|
+
.flex-shrink\:0 { flex-shrink: 0 !important; }
|
|
73
|
+
|
|
74
|
+
/* ===== OVERFLOW ===== */
|
|
75
|
+
.overflow\:hidden { overflow: hidden !important; }
|
|
76
|
+
.overflow\:auto { overflow: auto !important; }
|
|
77
|
+
|
|
78
|
+
/* ===== POSITION ===== */
|
|
79
|
+
.position\:relative { position: relative !important; }
|
|
80
|
+
.position\:absolute { position: absolute !important; }
|
|
81
|
+
.position\:fixed { position: fixed !important; }
|
|
82
|
+
.position\:sticky { position: sticky !important; }
|
|
83
|
+
|
|
84
|
+
/* ===== DISPLAY ===== */
|
|
85
|
+
.display\:none { display: none !important; }
|
|
86
|
+
.display\:block { display: block !important; }
|
|
87
|
+
.display\:inline { display: inline !important; }
|
|
88
|
+
.display\:inline-block { display: inline-block !important; }
|
|
89
|
+
.display\:flex { display: flex !important; }
|
|
90
|
+
.display\:grid { display: grid !important; }
|
|
91
|
+
|
|
92
|
+
/* ===== BORDERS ===== */
|
|
93
|
+
.border\:thin { border-width: var(--border-thin) !important; }
|
|
94
|
+
.border\:thick { border-width: var(--border-thick) !important; }
|
|
95
|
+
.border-radius\:s-2 { border-radius: var(--s-2) !important; }
|
|
96
|
+
.border-radius\:s-1 { border-radius: var(--s-1) !important; }
|
|
97
|
+
.border-radius\:s0 { border-radius: var(--s0) !important; }
|
|
98
|
+
|
|
99
|
+
/* ===== SHADOWS ===== */
|
|
100
|
+
.shadow\:small {
|
|
101
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24) !important;
|
|
102
|
+
}
|
|
103
|
+
.shadow\:medium {
|
|
104
|
+
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.12) !important;
|
|
105
|
+
}
|
|
106
|
+
.shadow\:large {
|
|
107
|
+
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15), 0 3px 6px rgba(0, 0, 0, 0.10) !important;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* ===== Z-INDEX ===== */
|
|
111
|
+
/* Use sparingly! Prefer source order. */
|
|
112
|
+
.z\:0 { z-index: 0 !important; }
|
|
113
|
+
.z\:1 { z-index: 1 !important; }
|
|
114
|
+
.z\:10 { z-index: 10 !important; }
|
|
115
|
+
.z\:100 { z-index: 100 !important; }
|
|
116
|
+
|
|
117
|
+
/* ===== LISTS ===== */
|
|
118
|
+
.list-style\:disc { list-style: disc !important; padding-inline-start: 1em !important; }
|
|
119
|
+
.list-style\:decimal { list-style: decimal !important; padding-inline-start: 1em !important; }
|
|
120
|
+
|
|
121
|
+
/* ===== CURSOR ===== */
|
|
122
|
+
.cursor\:pointer { cursor: pointer !important; }
|
|
123
|
+
.cursor\:not-allowed { cursor: not-allowed !important; }
|
|
124
|
+
|
|
125
|
+
/* ===== USER SELECT ===== */
|
|
126
|
+
.user-select\:none { user-select: none !important; }
|
|
127
|
+
.user-select\:all { user-select: all !important; }
|
|
128
|
+
|
|
129
|
+
/* ===== RATIO MODES ===== */
|
|
130
|
+
/*
|
|
131
|
+
* Switch the modular scale ratio for a container and all descendants.
|
|
132
|
+
* Golden (φ): Dramatic, high-impact - ideal for marketing, CTAs
|
|
133
|
+
* Silver (√2): Subtle, refined - ideal for documentation, dense content
|
|
134
|
+
* Fifth (1.5): Balanced middle-ground
|
|
135
|
+
*
|
|
136
|
+
* Also adjusts --measure (line length) to complement each ratio:
|
|
137
|
+
* Golden: 60ch (tighter), Fifth: 70ch (balanced), Silver: 80ch (looser)
|
|
138
|
+
*/
|
|
139
|
+
.ratio\:golden { --ratio: var(--ratio-golden) !important; --measure: 60ch !important; }
|
|
140
|
+
.ratio\:silver { --ratio: var(--ratio-silver) !important; --measure: 80ch !important; }
|
|
141
|
+
.ratio\:fifth { --ratio: var(--ratio-fifth) !important; --measure: 70ch !important; }
|
|
142
|
+
|
|
143
|
+
/* Aliases for convenience */
|
|
144
|
+
.ratio\:dramatic { --ratio: var(--ratio-golden) !important; --measure: 60ch !important; }
|
|
145
|
+
.ratio\:subtle { --ratio: var(--ratio-silver) !important; --measure: 80ch !important; }
|
|
146
|
+
.ratio\:balanced { --ratio: var(--ratio-fifth) !important; --measure: 70ch !important; }
|
|
147
|
+
|
|
148
|
+
/* Data attribute alternative (for JS toggling) */
|
|
149
|
+
[data-ratio="golden"] { --ratio: var(--ratio-golden); --measure: 60ch; }
|
|
150
|
+
[data-ratio="silver"] { --ratio: var(--ratio-silver); --measure: 80ch; }
|
|
151
|
+
[data-ratio="fifth"] { --ratio: var(--ratio-fifth); --measure: 70ch; }
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "elvish-css",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Intrinsic CSS layout-first styling primitives with Sindarin names",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"css",
|
|
7
|
+
"layout",
|
|
8
|
+
"custom-elements",
|
|
9
|
+
"web-components",
|
|
10
|
+
"intrinsic-design",
|
|
11
|
+
"view-transitions"
|
|
12
|
+
],
|
|
13
|
+
"author": "Mark Manley",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/star-this/elvish-css.git"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/star-this/elvish-css#readme",
|
|
20
|
+
"type": "module",
|
|
21
|
+
"main": "dist/elvish.umd.js",
|
|
22
|
+
"module": "dist/elvish.esm.js",
|
|
23
|
+
"types": "dist/elvish.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"import": "./dist/elvish.esm.js",
|
|
27
|
+
"require": "./dist/elvish.umd.js",
|
|
28
|
+
"types": "./dist/elvish.d.ts"
|
|
29
|
+
},
|
|
30
|
+
"./css": "./dist/elvish.css",
|
|
31
|
+
"./css/min": "./dist/elvish.min.css",
|
|
32
|
+
"./transitions": {
|
|
33
|
+
"import": "./global/transitions.js",
|
|
34
|
+
"types": "./dist/transitions.d.ts"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"global",
|
|
40
|
+
"primitives",
|
|
41
|
+
"elvish.css",
|
|
42
|
+
"elvish.js",
|
|
43
|
+
"README.md",
|
|
44
|
+
"LICENSE"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "node scripts/build.js",
|
|
48
|
+
"build:watch": "node scripts/build.js --watch",
|
|
49
|
+
"prepublishOnly": "npm run build"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"esbuild": "^0.20.0",
|
|
53
|
+
"lightningcss": "^1.24.0"
|
|
54
|
+
},
|
|
55
|
+
"browserslist": [
|
|
56
|
+
"last 2 Chrome versions",
|
|
57
|
+
"last 2 Firefox versions",
|
|
58
|
+
"last 2 Safari versions",
|
|
59
|
+
"last 2 Edge versions"
|
|
60
|
+
]
|
|
61
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adleithian Layout
|
|
3
|
+
*
|
|
4
|
+
* Establishes a container query context.
|
|
5
|
+
* The escape hatch for when intrinsic layouts need manual intervention.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
i-adleithian {
|
|
9
|
+
display: block;
|
|
10
|
+
adleithian-type: inline-size;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* Named containers use the name attribute */
|
|
14
|
+
i-adleithian[name] {
|
|
15
|
+
adleithian-name: attr(name);
|
|
16
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adleithian Layout Custom Element
|
|
3
|
+
*
|
|
4
|
+
* Establishes a container query context.
|
|
5
|
+
*
|
|
6
|
+
* @property {string} name - Adleithian name for targeted queries (optional)
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* <i-adleithian name="card">
|
|
10
|
+
* <div class="card">...</div>
|
|
11
|
+
* </i-adleithian>
|
|
12
|
+
*
|
|
13
|
+
* CSS:
|
|
14
|
+
* @container card (width < 300px) {
|
|
15
|
+
* .card { flex-direction: column; }
|
|
16
|
+
* }
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
class AdleithianLayout extends HTMLElement {
|
|
20
|
+
static get observedAttributes() {
|
|
21
|
+
return ['name'];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
constructor() {
|
|
25
|
+
super();
|
|
26
|
+
this.render = this.render.bind(this);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
connectedCallback() {
|
|
30
|
+
this.render();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
attributeChangedCallback() {
|
|
34
|
+
this.render();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get name() {
|
|
38
|
+
return this.getAttribute('name');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
set name(val) {
|
|
42
|
+
if (val) {
|
|
43
|
+
this.setAttribute('name', val);
|
|
44
|
+
} else {
|
|
45
|
+
this.removeAttribute('name');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
render() {
|
|
50
|
+
// Set adleithian-name via style if provided
|
|
51
|
+
if (this.name) {
|
|
52
|
+
this.style.containerName = this.name;
|
|
53
|
+
} else {
|
|
54
|
+
this.style.containerName = '';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if ('customElements' in window) {
|
|
60
|
+
customElements.define('i-adleithian', AdleithianLayout);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default AdleithianLayout;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Box Layout (i-bau)
|
|
3
|
+
*
|
|
4
|
+
* A container primitive focused on padding/structure.
|
|
5
|
+
* Visual styling (borders, backgrounds) is opt-in via attributes.
|
|
6
|
+
*
|
|
7
|
+
* Layout-first philosophy: invisible by default, styled explicitly.
|
|
8
|
+
*
|
|
9
|
+
* Attributes:
|
|
10
|
+
* padding="..." - Override padding (default: var(--s1))
|
|
11
|
+
* border - Add border
|
|
12
|
+
* border-width="..."- Custom border width
|
|
13
|
+
* bg - Add background color
|
|
14
|
+
* invert - Invert colors (dark bg, light text)
|
|
15
|
+
* compact - Remove padding
|
|
16
|
+
* borderless - Explicitly remove border (for overriding)
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
i-bau {
|
|
20
|
+
display: block;
|
|
21
|
+
padding: var(--bau-padding, var(--s1));
|
|
22
|
+
|
|
23
|
+
/* Color tokens - can be overridden per-instance */
|
|
24
|
+
--bau-color-light: var(--color-surface-raised, var(--color-light));
|
|
25
|
+
--bau-color-dark: var(--color-text, var(--color-dark));
|
|
26
|
+
--bau-border-color: var(--color-border, currentColor);
|
|
27
|
+
|
|
28
|
+
/* Layout-first: no visual styling by default */
|
|
29
|
+
/* Border width and background are 0/transparent from reset.css */
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* ===== VISUAL STYLING (Opt-in) ===== */
|
|
33
|
+
|
|
34
|
+
/* Add border - use [border] attribute */
|
|
35
|
+
i-bau[border] {
|
|
36
|
+
border-width: var(--bau-border-width, var(--border-thin, 1px));
|
|
37
|
+
border-color: var(--bau-border-color);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* Custom border width */
|
|
41
|
+
i-bau[border-width] {
|
|
42
|
+
border-width: var(--bau-border-width, var(--border-thin, 1px));
|
|
43
|
+
border-color: var(--bau-border-color);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Add background - use [bg] attribute */
|
|
47
|
+
i-bau[bg] {
|
|
48
|
+
background-color: var(--bau-color-light);
|
|
49
|
+
color: var(--bau-color-dark);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Inverted color scheme (implies bg) */
|
|
53
|
+
i-bau[invert] {
|
|
54
|
+
background-color: var(--bau-color-dark);
|
|
55
|
+
color: var(--bau-color-light);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Combined: border + background */
|
|
59
|
+
i-bau[border][bg],
|
|
60
|
+
i-bau[border][invert] {
|
|
61
|
+
border-width: var(--bau-border-width, var(--border-thin, 1px));
|
|
62
|
+
border-color: var(--bau-border-color);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* ===== LAYOUT VARIANTS ===== */
|
|
66
|
+
|
|
67
|
+
/* No padding */
|
|
68
|
+
i-bau[compact] {
|
|
69
|
+
padding: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Explicitly no border (for overriding inherited styles) */
|
|
73
|
+
i-bau[borderless] {
|
|
74
|
+
border-width: 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* ===== HIGH CONTRAST MODE ===== */
|
|
78
|
+
/* Transparent outline for Windows High Contrast Mode */
|
|
79
|
+
@media (forced-colors: active) {
|
|
80
|
+
i-bau[border],
|
|
81
|
+
i-bau[bg],
|
|
82
|
+
i-bau[invert] {
|
|
83
|
+
outline: var(--bau-border-width, 1px) solid transparent;
|
|
84
|
+
outline-offset: calc(var(--bau-border-width, 1px) * -1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Box Layout Custom Element
|
|
3
|
+
*
|
|
4
|
+
* A simple container with padding and optional border/background.
|
|
5
|
+
*
|
|
6
|
+
* @property {string} padding - A CSS padding value (default: var(--s1))
|
|
7
|
+
* @property {string} borderWidth - A CSS border-width value (default: var(--border-thin))
|
|
8
|
+
* @property {boolean} invert - Swap foreground and background colors
|
|
9
|
+
* @property {boolean} borderless - Remove border
|
|
10
|
+
* @property {boolean} compact - Remove padding
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <i-bau padding="var(--s2)" invert>
|
|
14
|
+
* <p>Content in a box</p>
|
|
15
|
+
* </i-bau>
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
class BauLayout extends HTMLElement {
|
|
19
|
+
static get observedAttributes() {
|
|
20
|
+
return ['padding', 'border-width', 'invert', 'borderless', 'compact'];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
constructor() {
|
|
24
|
+
super();
|
|
25
|
+
this.render = this.render.bind(this);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
connectedCallback() {
|
|
29
|
+
this.render();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
attributeChangedCallback() {
|
|
33
|
+
this.render();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get padding() {
|
|
37
|
+
return this.getAttribute('padding') || 'var(--s1)';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
set padding(val) {
|
|
41
|
+
this.setAttribute('padding', val);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get borderWidth() {
|
|
45
|
+
return this.getAttribute('border-width') || 'var(--border-thin)';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
set borderWidth(val) {
|
|
49
|
+
this.setAttribute('border-width', val);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get invert() {
|
|
53
|
+
return this.hasAttribute('invert');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
set invert(val) {
|
|
57
|
+
if (val) {
|
|
58
|
+
this.setAttribute('invert', '');
|
|
59
|
+
} else {
|
|
60
|
+
this.removeAttribute('invert');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get borderless() {
|
|
65
|
+
return this.hasAttribute('borderless');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
set borderless(val) {
|
|
69
|
+
if (val) {
|
|
70
|
+
this.setAttribute('borderless', '');
|
|
71
|
+
} else {
|
|
72
|
+
this.removeAttribute('borderless');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get compact() {
|
|
77
|
+
return this.hasAttribute('compact');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
set compact(val) {
|
|
81
|
+
if (val) {
|
|
82
|
+
this.setAttribute('compact', '');
|
|
83
|
+
} else {
|
|
84
|
+
this.removeAttribute('compact');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
render() {
|
|
89
|
+
// Set CSS custom properties for this instance
|
|
90
|
+
this.style.setProperty('--bau-padding', this.padding);
|
|
91
|
+
this.style.setProperty('--bau-border-width', this.borderWidth);
|
|
92
|
+
|
|
93
|
+
// Generate unique identifier
|
|
94
|
+
const invertStr = this.invert ? '-invert' : '';
|
|
95
|
+
const borderlessStr = this.borderless ? '-borderless' : '';
|
|
96
|
+
const compactStr = this.compact ? '-compact' : '';
|
|
97
|
+
const id = `Bau-${this.padding}-${this.borderWidth}${invertStr}${borderlessStr}${compactStr}`.replace(/[^\w-]/g, '');
|
|
98
|
+
|
|
99
|
+
this.dataset.i = id;
|
|
100
|
+
|
|
101
|
+
// Check if styles already exist
|
|
102
|
+
if (!document.getElementById(id)) {
|
|
103
|
+
const styleEl = document.createElement('style');
|
|
104
|
+
styleEl.id = id;
|
|
105
|
+
|
|
106
|
+
const selector = `[data-i="${id}"]`;
|
|
107
|
+
let css = `${selector} { padding: ${this.padding}; border-width: ${this.borderWidth}; }`;
|
|
108
|
+
|
|
109
|
+
if (this.borderless) {
|
|
110
|
+
css += `${selector} { border-width: 0; }`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (this.compact) {
|
|
114
|
+
css += `${selector} { padding: 0; }`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
styleEl.textContent = css;
|
|
118
|
+
document.head.appendChild(styleEl);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if ('customElements' in window) {
|
|
124
|
+
customElements.define('i-bau', BauLayout);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export default BauLayout;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Center Layout
|
|
3
|
+
*
|
|
4
|
+
* Horizontally centers content with a maximum width.
|
|
5
|
+
* Preserves gutters (minimum space on sides) in narrow contexts.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
i-enedh {
|
|
9
|
+
display: block;
|
|
10
|
+
|
|
11
|
+
/* Use content-box so padding adds to the max-width, not subtracts */
|
|
12
|
+
box-sizing: content-box;
|
|
13
|
+
|
|
14
|
+
/* Center with auto margins */
|
|
15
|
+
margin-inline: auto;
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* Maximum width - JS sets --enedh-max from the max attribute.
|
|
19
|
+
* Fallback chain: attribute value → 100% (full width until JS runs)
|
|
20
|
+
* This ensures layouts work even if JS fails to load.
|
|
21
|
+
*/
|
|
22
|
+
max-inline-size: var(--enedh-max, 100%);
|
|
23
|
+
|
|
24
|
+
/* Gutters - minimum space on either side */
|
|
25
|
+
padding-inline: var(--enedh-gutters, 0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Intrinsic centering - center children based on their content width */
|
|
29
|
+
i-enedh[intrinsic] {
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
align-items: center;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Also center the text */
|
|
36
|
+
i-enedh[and-text] {
|
|
37
|
+
text-align: center;
|
|
38
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Center Layout Custom Element
|
|
3
|
+
*
|
|
4
|
+
* Horizontally centers content with a maximum width.
|
|
5
|
+
*
|
|
6
|
+
* @property {string} max - Maximum width (default: var(--measure))
|
|
7
|
+
* @property {string} gutters - Minimum space on sides (default: 0)
|
|
8
|
+
* @property {boolean} intrinsic - Center children based on their content width
|
|
9
|
+
* @property {boolean} andText - Also center text alignment
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* <i-enedh max="40ch" gutters="var(--s1)">
|
|
13
|
+
* <p>Centered content</p>
|
|
14
|
+
* </i-enedh>
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
class EnedhLayout extends HTMLElement {
|
|
18
|
+
static get observedAttributes() {
|
|
19
|
+
return ['max', 'gutters', 'intrinsic', 'and-text'];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
constructor() {
|
|
23
|
+
super();
|
|
24
|
+
this.render = this.render.bind(this);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
connectedCallback() {
|
|
28
|
+
this.render();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
attributeChangedCallback() {
|
|
32
|
+
this.render();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get max() {
|
|
36
|
+
return this.getAttribute('max') || 'var(--measure)';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
set max(val) {
|
|
40
|
+
this.setAttribute('max', val);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get gutters() {
|
|
44
|
+
return this.getAttribute('gutters') || '0';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
set gutters(val) {
|
|
48
|
+
this.setAttribute('gutters', val);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get intrinsic() {
|
|
52
|
+
return this.hasAttribute('intrinsic');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
set intrinsic(val) {
|
|
56
|
+
if (val) {
|
|
57
|
+
this.setAttribute('intrinsic', '');
|
|
58
|
+
} else {
|
|
59
|
+
this.removeAttribute('intrinsic');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get andText() {
|
|
64
|
+
return this.hasAttribute('and-text');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
set andText(val) {
|
|
68
|
+
if (val) {
|
|
69
|
+
this.setAttribute('and-text', '');
|
|
70
|
+
} else {
|
|
71
|
+
this.removeAttribute('and-text');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
render() {
|
|
76
|
+
this.style.setProperty('--enedh-max', this.max);
|
|
77
|
+
this.style.setProperty('--enedh-gutters', this.gutters);
|
|
78
|
+
|
|
79
|
+
const intrinsicStr = this.intrinsic ? '-intrinsic' : '';
|
|
80
|
+
const textStr = this.andText ? '-andText' : '';
|
|
81
|
+
const id = `Enedh-${this.max}-${this.gutters}${intrinsicStr}${textStr}`.replace(/[^\w-]/g, '');
|
|
82
|
+
|
|
83
|
+
this.dataset.i = id;
|
|
84
|
+
|
|
85
|
+
if (!document.getElementById(id)) {
|
|
86
|
+
const styleEl = document.createElement('style');
|
|
87
|
+
styleEl.id = id;
|
|
88
|
+
|
|
89
|
+
const selector = `[data-i="${id}"]`;
|
|
90
|
+
let css = `${selector} { max-inline-size: ${this.max}; padding-inline: ${this.gutters}; }`;
|
|
91
|
+
|
|
92
|
+
if (this.intrinsic) {
|
|
93
|
+
css += `${selector} { display: flex; flex-direction: column; align-items: center; }`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (this.andText) {
|
|
97
|
+
css += `${selector} { text-align: center; }`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
styleEl.textContent = css;
|
|
101
|
+
document.head.appendChild(styleEl);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if ('customElements' in window) {
|
|
107
|
+
customElements.define('i-enedh', EnedhLayout);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default EnedhLayout;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cover Layout
|
|
3
|
+
*
|
|
4
|
+
* Vertically centers a principal element with optional
|
|
5
|
+
* header and footer elements. Perfect for hero sections.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
i-esgal {
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
min-block-size: var(--esgal-min-height, 100vh);
|
|
12
|
+
padding: var(--esgal-space, var(--s1));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
i-esgal > * {
|
|
16
|
+
margin-block: var(--esgal-space, var(--s1));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* The centered element - default is h1 */
|
|
20
|
+
i-esgal > :first-child:not(h1, h2, h3, [data-centered]) {
|
|
21
|
+
margin-block-start: 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
i-esgal > :last-child:not(h1, h2, h3, [data-centered]) {
|
|
25
|
+
margin-block-end: 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Elements that should be centered */
|
|
29
|
+
i-esgal > h1,
|
|
30
|
+
i-esgal > h2,
|
|
31
|
+
i-esgal > h3,
|
|
32
|
+
i-esgal > [data-centered] {
|
|
33
|
+
margin-block: auto;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* No padding variant */
|
|
37
|
+
i-esgal[no-pad] {
|
|
38
|
+
padding: 0;
|
|
39
|
+
}
|