@rettangoli/ui 1.0.5 → 1.0.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rettangoli/ui",
3
- "version": "1.0.5",
3
+ "version": "1.0.8",
4
4
  "description": "A UI component library for building web interfaces.",
5
5
  "main": "dist/rettangoli-esm.min.js",
6
6
  "type": "module",
@@ -19,7 +19,8 @@
19
19
  "module": "./src/index.js",
20
20
  "repository": {
21
21
  "type": "git",
22
- "url": "git+https://github.com/yuusoft-org/rettangoli.git"
22
+ "url": "https://github.com/yuusoft-org/rettangoli",
23
+ "directory": "packages/rettangoli-ui"
23
24
  },
24
25
  "author": {
25
26
  "name": "Luciano Hanyon Wu",
@@ -36,7 +37,7 @@
36
37
  "build": "rtgl fe build -o ./.generated/fe-entry.js && bun run esbuild.js && bun run esbuild-dev.js && npm run copy:css",
37
38
  "prepack": "npm run build",
38
39
  "vt:generate": "bun run build:dev && rtgl vt generate",
39
- "vt:docker": "bun run build:dev && bash -lc 'IMAGE=\"han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.0.0-rc27\"; docker pull \"$IMAGE\" >/dev/null 2>&1 || IMAGE=\"han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.0.0-rc26\"; docker run --rm --user $(id -u):$(id -g) -v \"$PWD:/app\" -w /app \"$IMAGE\" rtgl vt screenshot'",
40
+ "vt:docker": "bun run build:dev && bash -lc 'IMAGE=\"han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.0.5\"; docker pull \"$IMAGE\" >/dev/null 2>&1 || IMAGE=\"han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.0.0-rc27\"; docker run --rm --user $(id -u):$(id -g) -v \"$PWD:/app\" -w /app \"$IMAGE\" rtgl vt screenshot'",
40
41
  "vt:report": "bun run vt:docker && rtgl vt report",
41
42
  "vt:accept": "rtgl vt accept",
42
43
  "serve": "bunx serve .rettangoli/vt/_site"
@@ -61,12 +62,7 @@
61
62
  },
62
63
  "homepage": "https://github.com/yuusoft-org/rettangoli#readme",
63
64
  "dependencies": {
64
- "@floating-ui/dom": "^1.6.13",
65
- "@rettangoli/fe": "1.0.3",
66
- "commander": "^13.1.0",
67
- "jempl": "1.0.0",
68
- "js-yaml": "^4.1.0",
69
- "liquidjs": "^10.21.0",
70
- "snabbdom": "^3.6.2"
65
+ "@rettangoli/fe": "1.0.4",
66
+ "jempl": "1.0.1"
71
67
  }
72
68
  }
@@ -0,0 +1,22 @@
1
+ const normalizeAspectRatioValue = (value) => {
2
+ return `${value}`.trim().replace(/\s*\/\s*/g, "/");
3
+ };
4
+
5
+ export const normalizeAspectRatio = (value) => {
6
+ if (value === undefined || value === null) {
7
+ return undefined;
8
+ }
9
+
10
+ const normalizedValue = normalizeAspectRatioValue(value);
11
+ if (normalizedValue.length === 0) {
12
+ return undefined;
13
+ }
14
+
15
+ if (typeof CSS !== "undefined" && typeof CSS.supports === "function") {
16
+ return CSS.supports("aspect-ratio", normalizedValue)
17
+ ? normalizedValue
18
+ : undefined;
19
+ }
20
+
21
+ return normalizedValue;
22
+ };
package/src/common.js CHANGED
@@ -262,3 +262,5 @@ export {
262
262
  applyDimensionToStyleBucket,
263
263
  applyInlineWidthDimension,
264
264
  } from "./common/dimensions.js";
265
+
266
+ export { normalizeAspectRatio } from "./common/aspectRatio.js";
@@ -0,0 +1,15 @@
1
+ componentName: rtgl-card
2
+ propsSchema:
3
+ type: object
4
+ properties:
5
+ head:
6
+ type: string
7
+ desc:
8
+ type: string
9
+ size:
10
+ type: string
11
+ enum: [sm, md, lg]
12
+ events: []
13
+ methods:
14
+ type: object
15
+ properties: {}
@@ -0,0 +1,87 @@
1
+ const blacklistedProps = [
2
+ 'id',
3
+ 'class',
4
+ 'style',
5
+ 'slot',
6
+ 'head',
7
+ 'desc',
8
+ 'size',
9
+ 'd',
10
+ 'ah',
11
+ 'av',
12
+ 'wrap',
13
+ 'noWrap',
14
+ 'g',
15
+ 'gh',
16
+ 'gv',
17
+ 'p',
18
+ 'pt',
19
+ 'pr',
20
+ 'pb',
21
+ 'pl',
22
+ 'pv',
23
+ 'ph',
24
+ 'bw',
25
+ 'bwt',
26
+ 'bwr',
27
+ 'bwb',
28
+ 'bwl',
29
+ 'bc',
30
+ 'br',
31
+ 'shadow',
32
+ 'bgc',
33
+ 'href',
34
+ 'newTab',
35
+ 'rel',
36
+ 'cur',
37
+ 'sv',
38
+ 'sh',
39
+ 'overflow',
40
+ ];
41
+
42
+ const sizePresets = {
43
+ sm: {
44
+ cardAttrString: 'p=md sm-p=sm g=md sm-g=sm',
45
+ headerAttrString: 'g=xs',
46
+ headingSize: 'lg',
47
+ subheadingSize: 'sm',
48
+ },
49
+ md: {
50
+ cardAttrString: 'p=lg md-p=md sm-p=md g=lg md-g=md sm-g=md',
51
+ headerAttrString: 'g=sm',
52
+ headingSize: 'h4',
53
+ subheadingSize: 'sm',
54
+ },
55
+ lg: {
56
+ cardAttrString: 'p=xl lg-p=lg md-p=md sm-p=md g=lg md-g=md sm-g=md',
57
+ headerAttrString: 'g=sm',
58
+ headingSize: 'h3',
59
+ subheadingSize: 'md',
60
+ },
61
+ };
62
+
63
+ const stringifyProps = (props = {}) => {
64
+ return Object.entries(props)
65
+ .filter(([key]) => !blacklistedProps.includes(key))
66
+ .map(([key, value]) => `${key}=${value}`)
67
+ .join(' ');
68
+ };
69
+
70
+ export const createInitialState = () => Object.freeze({});
71
+
72
+ export const selectViewData = ({ props = {} }) => {
73
+ const size = sizePresets[props.size] ? props.size : 'md';
74
+ const preset = sizePresets[size];
75
+
76
+ return {
77
+ containerAttrString: stringifyProps(props),
78
+ cardAttrString: preset.cardAttrString,
79
+ headerAttrString: preset.headerAttrString,
80
+ headingSize: preset.headingSize,
81
+ subheadingSize: preset.subheadingSize,
82
+ head: props.head || '',
83
+ desc: props.desc || '',
84
+ hasHeader: !!(props.head || props.desc),
85
+ size,
86
+ };
87
+ };
@@ -0,0 +1,18 @@
1
+ styles:
2
+ :host:
3
+ display: block
4
+ slot:
5
+ display: block
6
+ min-width: 0
7
+ .rtgl-card-body:
8
+ min-width: 0
9
+ template:
10
+ - 'rtgl-view class="rtgl-card" d=v w=f bgc=bg bw=xs bc=bo br=xl shadow=sm ${cardAttrString} ${containerAttrString}':
11
+ - $if hasHeader:
12
+ - 'rtgl-view class="rtgl-card-header" d=v w=f ${headerAttrString}':
13
+ - $if head:
14
+ - rtgl-text class="rtgl-card-heading" s=${headingSize} w=f: ${head}
15
+ - $if desc:
16
+ - rtgl-text class="rtgl-card-desc" s=${subheadingSize} c=mu-fg w=f: ${desc}
17
+ - div class=rtgl-card-body:
18
+ - slot: null
@@ -1,4 +1,5 @@
1
1
  import RettangoliButton from './primitives/button.js'
2
+ import RettangoliGrid from './primitives/grid.js';
2
3
  import RettangoliView from './primitives/view.js';
3
4
  import RettangoliText from './primitives/text.js';
4
5
  import RettangoliImage from './primitives/image.js';
@@ -17,6 +18,7 @@ import RettangoliPopover from './primitives/popover.js';
17
18
 
18
19
 
19
20
  customElements.define("rtgl-button", RettangoliButton({}));
21
+ customElements.define("rtgl-grid", RettangoliGrid({}));
20
22
  customElements.define("rtgl-view", RettangoliView({}));
21
23
  customElements.define("rtgl-text", RettangoliText({}));
22
24
  customElements.define("rtgl-image", RettangoliImage({}));
@@ -1,4 +1,5 @@
1
1
  import RettangoliButton from './primitives/button.js'
2
+ import RettangoliGrid from './primitives/grid.js';
2
3
  import RettangoliView from './primitives/view.js';
3
4
  import RettangoliText from './primitives/text.js';
4
5
  import RettangoliImage from './primitives/image.js';
@@ -17,6 +18,7 @@ import RettangoliDialog from './primitives/dialog.js';
17
18
  import RettangoliPopover from './primitives/popover.js';
18
19
 
19
20
  customElements.define("rtgl-button", RettangoliButton({}));
21
+ customElements.define("rtgl-grid", RettangoliGrid({}));
20
22
  customElements.define("rtgl-view", RettangoliView({}));
21
23
  customElements.define("rtgl-text", RettangoliText({}));
22
24
  customElements.define("rtgl-image", RettangoliImage({}));
package/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import RettangoliButton from './primitives/button.js'
2
+ import RettangoliGrid from './primitives/grid.js';
2
3
  import RettangoliView from './primitives/view.js';
3
4
  import RettangoliText from './primitives/text.js';
4
5
  import RettangoliImage from './primitives/image.js';
@@ -19,6 +20,7 @@ import createGlobalUI from './deps/createGlobalUI.js';
19
20
 
20
21
  export {
21
22
  RettangoliButton,
23
+ RettangoliGrid,
22
24
  RettangoliView,
23
25
  RettangoliText,
24
26
  RettangoliImage,
@@ -0,0 +1,220 @@
1
+ import {
2
+ css,
3
+ dimensionWithUnit,
4
+ convertObjectToCssString,
5
+ styleMapKeys,
6
+ permutateBreakpoints,
7
+ overlayLinkStyles,
8
+ syncLinkOverlay,
9
+ createResponsiveStyleBuckets,
10
+ responsiveStyleSizes,
11
+ applyDimensionToStyleBucket,
12
+ } from "../common.js";
13
+ import cursorStyles from "../styles/cursorStyles.js";
14
+ import scrollStyle from "../styles/scrollStyles.js";
15
+ import stylesGenerator from "../styles/viewStyles.js";
16
+ import marginStyles from "../styles/marginStyles.js";
17
+ import anchorStyles from "../styles/anchorStyles.js";
18
+
19
+ const resolveGridTemplateColumns = (cols) => {
20
+ if (cols == null) {
21
+ return null;
22
+ }
23
+
24
+ const normalizedCols = cols.trim();
25
+ if (normalizedCols === "") {
26
+ return null;
27
+ }
28
+
29
+ if (/^[1-9]\d*$/.test(normalizedCols)) {
30
+ return `repeat(${normalizedCols}, minmax(0, 1fr))`;
31
+ }
32
+
33
+ return normalizedCols;
34
+ };
35
+
36
+ class RettangoliGridElement extends HTMLElement {
37
+ static styleSheet = null;
38
+
39
+ static initializeStyleSheet() {
40
+ if (!RettangoliGridElement.styleSheet) {
41
+ RettangoliGridElement.styleSheet = new CSSStyleSheet();
42
+ RettangoliGridElement.styleSheet.replaceSync(css`
43
+ slot {
44
+ display: contents;
45
+ }
46
+ :host {
47
+ display: grid;
48
+ grid-template-columns: repeat(1, minmax(0, 1fr));
49
+ align-self: auto;
50
+ border-style: solid;
51
+ border-width: 0;
52
+ box-sizing: border-box;
53
+ border-color: var(--border);
54
+ }
55
+
56
+ ${scrollStyle}
57
+ ${marginStyles}
58
+ ${cursorStyles}
59
+ ${stylesGenerator}
60
+ ${anchorStyles}
61
+ ${overlayLinkStyles}
62
+ `);
63
+ }
64
+ }
65
+
66
+ constructor() {
67
+ super();
68
+ RettangoliGridElement.initializeStyleSheet();
69
+ this.shadow = this.attachShadow({ mode: "open" });
70
+ this.shadow.adoptedStyleSheets = [RettangoliGridElement.styleSheet];
71
+
72
+ this._styleElement = document.createElement("style");
73
+ this._slotElement = document.createElement("slot");
74
+ this._linkElement = null;
75
+
76
+ this.shadow.appendChild(this._styleElement);
77
+ this._updateDOM();
78
+ }
79
+
80
+ static get observedAttributes() {
81
+ return [
82
+ "href",
83
+ "new-tab",
84
+ "rel",
85
+ ...permutateBreakpoints([
86
+ ...styleMapKeys,
87
+ "cols",
88
+ "op",
89
+ "wh",
90
+ "w",
91
+ "h",
92
+ "hide",
93
+ "show",
94
+ "sh",
95
+ "sv",
96
+ "z",
97
+ "overflow",
98
+ ]),
99
+ ];
100
+ }
101
+
102
+ _styles = createResponsiveStyleBuckets();
103
+
104
+ _lastStyleString = "";
105
+
106
+ _updateDOM() {
107
+ const href = this.getAttribute("href");
108
+ const newTab = this.hasAttribute("new-tab");
109
+ const rel = this.getAttribute("rel");
110
+
111
+ this._linkElement = syncLinkOverlay({
112
+ shadowRoot: this.shadow,
113
+ slotElement: this._slotElement,
114
+ linkElement: this._linkElement,
115
+ href,
116
+ newTab,
117
+ rel,
118
+ });
119
+ }
120
+
121
+ connectedCallback() {
122
+ this.updateStyles();
123
+ }
124
+
125
+ updateStyles() {
126
+ this._styles = createResponsiveStyleBuckets();
127
+
128
+ responsiveStyleSizes.forEach((size) => {
129
+ const addSizePrefix = (tag) => {
130
+ return `${size === "default" ? "" : `${size}-`}${tag}`;
131
+ };
132
+
133
+ const wh = this.getAttribute(addSizePrefix("wh"));
134
+ const width = dimensionWithUnit(
135
+ wh === null ? this.getAttribute(addSizePrefix("w")) : wh,
136
+ );
137
+ const height = dimensionWithUnit(
138
+ wh === null ? this.getAttribute(addSizePrefix("h")) : wh,
139
+ );
140
+ const cols = resolveGridTemplateColumns(
141
+ this.getAttribute(addSizePrefix("cols")),
142
+ );
143
+ const opacity = this.getAttribute(addSizePrefix("op"));
144
+ const zIndex = this.getAttribute(addSizePrefix("z"));
145
+
146
+ if (cols !== null) {
147
+ this._styles[size]["grid-template-columns"] = cols;
148
+ }
149
+
150
+ if (zIndex !== null) {
151
+ this._styles[size]["z-index"] = zIndex;
152
+ }
153
+
154
+ if (opacity !== null) {
155
+ this._styles[size].opacity = opacity;
156
+ }
157
+
158
+ applyDimensionToStyleBucket({
159
+ styleBucket: this._styles[size],
160
+ axis: "width",
161
+ dimension: width,
162
+ fillValue: "var(--width-stretch)",
163
+ allowFlexGrow: true,
164
+ });
165
+
166
+ applyDimensionToStyleBucket({
167
+ styleBucket: this._styles[size],
168
+ axis: "height",
169
+ dimension: height,
170
+ fillValue: "100%",
171
+ allowFlexGrow: true,
172
+ });
173
+
174
+ if (this.hasAttribute(addSizePrefix("hide"))) {
175
+ this._styles[size].display = "none";
176
+ }
177
+
178
+ if (this.hasAttribute(addSizePrefix("show"))) {
179
+ this._styles[size].display = "grid";
180
+ }
181
+
182
+ const scrollHorizontal = this.hasAttribute(addSizePrefix("sh"));
183
+ const scrollVertical = this.hasAttribute(addSizePrefix("sv"));
184
+ const overflow = this.getAttribute(addSizePrefix("overflow"));
185
+
186
+ if (scrollHorizontal && scrollVertical) {
187
+ this._styles[size].overflow = "scroll";
188
+ } else if (scrollHorizontal) {
189
+ this._styles[size]["overflow-x"] = "scroll";
190
+ } else if (scrollVertical) {
191
+ this._styles[size]["overflow-y"] = "scroll";
192
+ }
193
+
194
+ if (overflow === "hidden") {
195
+ this._styles[size].overflow = "hidden";
196
+ }
197
+ });
198
+
199
+ const newStyleString = convertObjectToCssString(this._styles);
200
+ if (newStyleString !== this._lastStyleString) {
201
+ this._styleElement.textContent = newStyleString;
202
+ this._lastStyleString = newStyleString;
203
+ }
204
+ }
205
+
206
+ attributeChangedCallback(name, oldValue, newValue) {
207
+ if (name === "href" || name === "new-tab" || name === "rel") {
208
+ this._updateDOM();
209
+ return;
210
+ }
211
+
212
+ if (oldValue !== newValue) {
213
+ this.updateStyles();
214
+ }
215
+ }
216
+ }
217
+
218
+ export default ({ render, html }) => {
219
+ return RettangoliGridElement;
220
+ };
@@ -8,6 +8,7 @@ import {
8
8
  createResponsiveStyleBuckets,
9
9
  responsiveStyleSizes,
10
10
  applyDimensionToStyleBucket,
11
+ normalizeAspectRatio,
11
12
  } from "../common.js";
12
13
  import cursorStyles from "../styles/cursorStyles.js";
13
14
  import anchorStyles from "../styles/anchorStyles.js";
@@ -90,6 +91,7 @@ class RettangoliImageElement extends HTMLElement {
90
91
  "wh",
91
92
  "w",
92
93
  "h",
94
+ "ar",
93
95
  "hide",
94
96
  "show",
95
97
  "op",
@@ -159,6 +161,9 @@ class RettangoliImageElement extends HTMLElement {
159
161
  );
160
162
  const opacity = this.getAttribute(addSizePrefix("op"));
161
163
  const zIndex = this.getAttribute(addSizePrefix("z"));
164
+ const aspectRatio = normalizeAspectRatio(
165
+ this.getAttribute(addSizePrefix("ar")),
166
+ );
162
167
 
163
168
  if (zIndex !== null) {
164
169
  this._styles[size]["z-index"] = zIndex;
@@ -168,6 +173,10 @@ class RettangoliImageElement extends HTMLElement {
168
173
  this._styles[size].opacity = opacity;
169
174
  }
170
175
 
176
+ if (aspectRatio !== undefined) {
177
+ this._styles[size]["aspect-ratio"] = aspectRatio;
178
+ }
179
+
171
180
  applyDimensionToStyleBucket({
172
181
  styleBucket: this._styles[size],
173
182
  axis: "width",
@@ -10,6 +10,7 @@ import {
10
10
  responsiveStyleSizes,
11
11
  applyDimensionToStyleBucket,
12
12
  getResponsiveAttribute,
13
+ normalizeAspectRatio,
13
14
  } from "../common.js";
14
15
  import flexDirectionStyles from "../styles/flexDirectionStyles.js";
15
16
  import cursorStyles from "../styles/cursorStyles.js";
@@ -78,6 +79,7 @@ class RettangoliViewElement extends HTMLElement {
78
79
  "wh",
79
80
  "w",
80
81
  "h",
82
+ "ar",
81
83
  "hide",
82
84
  "show",
83
85
  "sh",
@@ -136,6 +138,9 @@ class RettangoliViewElement extends HTMLElement {
136
138
  );
137
139
  const opacity = this.getAttribute(addSizePrefix("op"));
138
140
  const zIndex = this.getAttribute(addSizePrefix("z"));
141
+ const aspectRatio = normalizeAspectRatio(
142
+ this.getAttribute(addSizePrefix("ar")),
143
+ );
139
144
 
140
145
  if (zIndex !== null) {
141
146
  this._styles[size]["z-index"] = zIndex;
@@ -145,6 +150,10 @@ class RettangoliViewElement extends HTMLElement {
145
150
  this._styles[size].opacity = opacity;
146
151
  }
147
152
 
153
+ if (aspectRatio !== undefined) {
154
+ this._styles[size]["aspect-ratio"] = aspectRatio;
155
+ }
156
+
148
157
  applyDimensionToStyleBucket({
149
158
  styleBucket: this._styles[size],
150
159
  axis: "width",