@oscarpalmer/oui 0.19.0 → 0.20.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.
Files changed (50) hide show
  1. package/dist/css/a11y.css +0 -1
  2. package/dist/css/form.css +0 -1
  3. package/dist/css/popover.css +22 -0
  4. package/dist/css/reset.css +8 -8
  5. package/dist/css/table.css +1 -1
  6. package/dist/css/tooltip.css +43 -0
  7. package/dist/js/attributable.d.mts +4 -0
  8. package/dist/js/{attributable.full.js → attributable.mjs} +8 -1
  9. package/dist/js/floatable.d.mts +26 -0
  10. package/dist/js/{floatable.js → floatable.mjs} +73 -50
  11. package/dist/js/focus-trap/embedded.d.mts +26 -0
  12. package/dist/js/focus-trap/{embedded.js → embedded.mjs} +10 -8
  13. package/dist/js/focus-trap/standalone.d.mts +1 -0
  14. package/dist/js/focus-trap/{standalone.js → standalone.mjs} +5 -2
  15. package/dist/js/index.d.mts +4 -0
  16. package/dist/js/index.mjs +5 -0
  17. package/dist/js/popover.d.mts +20 -0
  18. package/dist/js/{popover.js → popover.mjs} +10 -8
  19. package/dist/js/splitter.d.mts +25 -0
  20. package/dist/js/{splitter.js → splitter.mjs} +58 -56
  21. package/dist/js/tooltip.d.mts +4 -0
  22. package/dist/js/{tooltip.js → tooltip.mjs} +20 -18
  23. package/package.json +64 -69
  24. package/src/css/mixins.scss +30 -1
  25. package/src/css/popover.scss +6 -1
  26. package/src/css/reset.scss +4 -4
  27. package/src/css/table.scss +1 -1
  28. package/src/css/tooltip.scss +55 -1
  29. package/src/js/attributable.ts +11 -1
  30. package/src/js/floatable.ts +136 -58
  31. package/src/js/focus-trap/embedded.ts +4 -10
  32. package/src/js/splitter.ts +2 -5
  33. package/src/js/tooltip.ts +5 -5
  34. package/dist/js/attributable.js +0 -36
  35. package/dist/js/floatable.full.js +0 -398
  36. package/dist/js/focus-trap/embedded.full.js +0 -408
  37. package/dist/js/focus-trap/standalone.full.js +0 -447
  38. package/dist/js/index.js +0 -5
  39. package/dist/js/oui.full.js +0 -1573
  40. package/dist/js/popover.full.js +0 -760
  41. package/dist/js/splitter.full.js +0 -769
  42. package/dist/js/tooltip.full.js +0 -613
  43. package/types/attributable.d.ts +0 -1
  44. package/types/floatable.d.ts +0 -24
  45. package/types/focus-trap/embedded.d.ts +0 -24
  46. package/types/focus-trap/standalone.d.ts +0 -1
  47. package/types/index.d.ts +0 -4
  48. package/types/popover.d.ts +0 -17
  49. package/types/splitter.d.ts +0 -23
  50. package/types/tooltip.d.ts +0 -2
@@ -5,6 +5,7 @@ import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
5
5
  import { round } from "@oscarpalmer/atoms/math";
6
6
  import { toggleStyles } from "@oscarpalmer/toretto/style";
7
7
  import supportsTouch from "@oscarpalmer/toretto/touch";
8
+ //#region src/js/splitter.ts
8
9
  var OuiSplitterElement = class extends HTMLElement {
9
10
  static observedAttributes = [
10
11
  "max",
@@ -63,7 +64,7 @@ var OuiSplitterElement = class extends HTMLElement {
63
64
  }
64
65
  }
65
66
  };
66
- var index = 0;
67
+ let index = 0;
67
68
  var Splitter = class {
68
69
  element;
69
70
  handle;
@@ -114,11 +115,11 @@ function createHandle() {
114
115
  handle.setAttribute(ATTRIBUTE_HANDLE, "");
115
116
  return handle;
116
117
  }
117
- function createSeparator(splitter$1) {
118
+ function createSeparator(splitter) {
118
119
  const separator = document.createElement("div");
119
120
  separator.role = "separator";
120
121
  separator.tabIndex = 0;
121
- separator.setAttribute("aria-controls", splitter$1.element.id);
122
+ separator.setAttribute("aria-controls", splitter.element.id);
122
123
  separator.setAttribute("aria-label", "Resize panels");
123
124
  separator.setAttribute(ATTRIBUTE_SEPARATOR, "");
124
125
  return separator;
@@ -126,20 +127,20 @@ function createSeparator(splitter$1) {
126
127
  function getContained(min, value, max) {
127
128
  return round(clamp(value, min, max), VALUE_DECIMALS);
128
129
  }
129
- function getSize(splitter$1, value) {
130
- const { height, left, top, width } = splitter$1.rectangle;
131
- const fraction = (value - (splitter$1.types.horizontal ? top : left)) / (splitter$1.types.horizontal ? height : width);
132
- return getContained(splitter$1.values.min, fraction, splitter$1.values.max);
130
+ function getSize(splitter, value) {
131
+ const { height, left, top, width } = splitter.rectangle;
132
+ const fraction = (value - (splitter.types.horizontal ? top : left)) / (splitter.types.horizontal ? height : width);
133
+ return getContained(splitter.values.min, fraction, splitter.values.max);
133
134
  }
134
- function getTypes(splitter$1, width, height) {
135
- const type = splitter$1.element.getAttribute("type")?.trim() ?? "";
135
+ function getTypes(splitter, width, height) {
136
+ const type = splitter.element.getAttribute("type")?.trim() ?? "";
136
137
  if (type === "horizontal") return {
137
138
  auto: false,
138
139
  horizontal: true
139
140
  };
140
141
  if (type === "auto") return {
141
142
  auto: true,
142
- horizontal: (height ?? splitter$1.rectangle.height) > (width ?? splitter$1.rectangle.width)
143
+ horizontal: (height ?? splitter.rectangle.height) > (width ?? splitter.rectangle.width)
143
144
  };
144
145
  return {
145
146
  auto: false,
@@ -189,34 +190,34 @@ function onKeydown(event) {
189
190
  }
190
191
  }
191
192
  function onNavigate(event) {
192
- const splitter$1 = MAPPED_ELEMENTS.get(findAncestor(event.target, "[oui-splitter-separator]"));
193
- if (splitter$1 == null) return;
194
- const { types, values } = splitter$1;
193
+ const splitter = MAPPED_ELEMENTS.get(findAncestor(event, "[oui-splitter-separator]"));
194
+ if (splitter == null) return;
195
+ const { types, values } = splitter;
195
196
  if (KEYS_ABSOLUTE.has(event.key)) {
196
- setSize(splitter$1, event.key === "End" ? values.max : values.min, true);
197
+ setSize(splitter, event.key === "End" ? values.max : values.min, true);
197
198
  return;
198
199
  }
199
200
  if (types.horizontal && !KEYS_HORIZONTAL.has(event.key) || !(types.horizontal || KEYS_VERTICAL.has(event.key))) return;
200
201
  const offset = KEYS_NEGATIVE.has(event.key) ? -1 : 1;
201
- setSize(splitter$1, getContained(values.min, values.now.current + offset * NAVIGATION_MODIFIER, values.max), true);
202
+ setSize(splitter, getContained(values.min, values.now.current + offset * NAVIGATION_MODIFIER, values.max), true);
202
203
  }
203
204
  function onObservation(entries) {
204
205
  if (frame != null) cancelAnimationFrame(frame);
205
206
  frame = requestAnimationFrame(() => {
206
207
  for (const entry of entries) {
207
- const splitter$1 = MAPPED_ELEMENTS.get(entry.target);
208
- if (splitter$1 == null) return;
209
- splitter$1.types = getTypes(splitter$1, entry.contentRect.width, entry.contentRect.height);
210
- if (splitter$1.types.horizontal) splitter$1.element.setAttribute(ATTRIBUTE_HORIZONTAL, "");
211
- else splitter$1.element.removeAttribute(ATTRIBUTE_HORIZONTAL);
212
- setAriaOrientation(splitter$1);
208
+ const splitter = MAPPED_ELEMENTS.get(entry.target);
209
+ if (splitter == null) return;
210
+ splitter.types = getTypes(splitter, entry.contentRect.width, entry.contentRect.height);
211
+ if (splitter.types.horizontal) splitter.element.setAttribute(ATTRIBUTE_HORIZONTAL, "");
212
+ else splitter.element.removeAttribute(ATTRIBUTE_HORIZONTAL);
213
+ setAriaOrientation(splitter);
213
214
  }
214
215
  frame = void 0;
215
216
  });
216
217
  }
217
218
  function onPointerdown(event) {
218
219
  if (event.type === "mousedown" && supportsTouch.value || event.type === "touchstart" && !supportsTouch.value) return;
219
- splitter = MAPPED_ELEMENTS.get(findAncestor(event.target, SELECTOR_HANDLE));
220
+ splitter = MAPPED_ELEMENTS.get(findAncestor(event, SELECTOR_HANDLE));
220
221
  if (splitter == null) return;
221
222
  if (supportsTouch.value) event.preventDefault();
222
223
  splitter.handle.setAttribute(ATTRIBUTE_ACTIVE, "");
@@ -235,51 +236,51 @@ function onPointermove(event) {
235
236
  function onPointerup() {
236
237
  if (splitter != null) onEnd(false);
237
238
  }
238
- function setAriaOrientation(splitter$1) {
239
- splitter$1.separator.setAttribute("aria-orientation", splitter$1.types.horizontal ? "horizontal" : "vertical");
239
+ function setAriaOrientation(splitter) {
240
+ splitter.separator.setAttribute("aria-orientation", splitter.types.horizontal ? "horizontal" : "vertical");
240
241
  }
241
- function setAriaValue(splitter$1) {
242
- splitter$1.separator.setAttribute("aria-valuemax", String(splitter$1.values.max));
243
- splitter$1.separator.setAttribute("aria-valuemin", String(splitter$1.values.min));
244
- splitter$1.separator.setAttribute("aria-valuenow", String(splitter$1.values.now.current));
242
+ function setAriaValue(splitter) {
243
+ splitter.separator.setAttribute("aria-valuemax", String(splitter.values.max));
244
+ splitter.separator.setAttribute("aria-valuemin", String(splitter.values.min));
245
+ splitter.separator.setAttribute("aria-valuenow", String(splitter.values.now.current));
245
246
  }
246
- function setSize(splitter$1, size, previous) {
247
- splitter$1.values.now.current = size;
248
- if (previous) splitter$1.values.now.previous = size;
249
- splitter$1.element.style.setProperty("--oui-splitter-size", `${size}`);
250
- setAriaValue(splitter$1);
247
+ function setSize(splitter, size, previous) {
248
+ splitter.values.now.current = size;
249
+ if (previous) splitter.values.now.previous = size;
250
+ splitter.element.style.setProperty("--oui-splitter-size", `${size}`);
251
+ setAriaValue(splitter);
251
252
  }
252
- var SELECTOR = "oui-splitter";
253
- var ATTRIBUTE_ACTIVE = `${SELECTOR}-active`;
254
- var ATTRIBUTE_HANDLE = `${SELECTOR}-handle`;
255
- var ATTRIBUTE_HORIZONTAL = `${SELECTOR}-horizontal`;
256
- var ATTRIBUTE_SEPARATOR = `${SELECTOR}-separator`;
257
- var KEYS_ABSOLUTE = new Set(["End", "Home"]);
258
- var KEYS_HORIZONTAL = new Set(["ArrowDown", "ArrowUp"]);
259
- var KEYS_NEGATIVE = new Set(["ArrowLeft", "ArrowUp"]);
260
- var KEYS_VERTICAL = new Set(["ArrowLeft", "ArrowRight"]);
261
- var KEYS_ALL = new Set([
253
+ const SELECTOR = "oui-splitter";
254
+ const ATTRIBUTE_ACTIVE = `${SELECTOR}-active`;
255
+ const ATTRIBUTE_HANDLE = `${SELECTOR}-handle`;
256
+ const ATTRIBUTE_HORIZONTAL = `${SELECTOR}-horizontal`;
257
+ const ATTRIBUTE_SEPARATOR = `${SELECTOR}-separator`;
258
+ const KEYS_ABSOLUTE = new Set(["End", "Home"]);
259
+ const KEYS_HORIZONTAL = new Set(["ArrowDown", "ArrowUp"]);
260
+ const KEYS_NEGATIVE = new Set(["ArrowLeft", "ArrowUp"]);
261
+ const KEYS_VERTICAL = new Set(["ArrowLeft", "ArrowRight"]);
262
+ const KEYS_ALL = new Set([
262
263
  ...KEYS_ABSOLUTE,
263
264
  ...KEYS_HORIZONTAL,
264
265
  ...KEYS_VERTICAL
265
266
  ]);
266
- var MAPPED_ELEMENTS = /* @__PURE__ */ new WeakMap();
267
- var METHODS_CONNECT = ["delete", "set"];
268
- var METHODS_OBSERVE = ["unobserve", "observe"];
269
- var NAVIGATION_MAXIMUM_PERCENTAGE = .9;
270
- var NAVIGATION_MAXIMUM_TOTAL = 100;
271
- var NAVIGATION_MINIMUM_PERCENTAGE = .1;
272
- var NAVIGATION_MODIFIER = .05;
273
- var RESIZE_OBSERVER = new ResizeObserver(onObservation);
274
- var SELECTOR_HANDLE = `[${ATTRIBUTE_HANDLE}]`;
275
- var STYLING_TOGGLER = toggleStyles(document.body, {
267
+ const MAPPED_ELEMENTS = /* @__PURE__ */ new WeakMap();
268
+ const METHODS_CONNECT = ["delete", "set"];
269
+ const METHODS_OBSERVE = ["unobserve", "observe"];
270
+ const NAVIGATION_MAXIMUM_PERCENTAGE = .9;
271
+ const NAVIGATION_MAXIMUM_TOTAL = 100;
272
+ const NAVIGATION_MINIMUM_PERCENTAGE = .1;
273
+ const NAVIGATION_MODIFIER = .05;
274
+ const RESIZE_OBSERVER = new ResizeObserver(onObservation);
275
+ const SELECTOR_HANDLE = `[${ATTRIBUTE_HANDLE}]`;
276
+ const STYLING_TOGGLER = toggleStyles(document.body, {
276
277
  touchAction: "none",
277
278
  userSelect: "none",
278
279
  webkitUserSelect: "none"
279
280
  });
280
- var VALUE_DECIMALS = 6;
281
- var frame;
282
- var splitter;
281
+ const VALUE_DECIMALS = 6;
282
+ let frame;
283
+ let splitter;
283
284
  customElements.define(SELECTOR, OuiSplitterElement);
284
285
  on(document, "keydown", onKeydown);
285
286
  on(document, "mousedown", onPointerdown);
@@ -287,4 +288,5 @@ on(document, "pointermove", onPointermove);
287
288
  on(document, "pointerup", onPointerup);
288
289
  on(document, "touchcancel", onPointerup, { passive: false });
289
290
  on(document, "touchstart", onPointerdown, { passive: false });
291
+ //#endregion
290
292
  export { OuiSplitterElement };
@@ -0,0 +1,4 @@
1
+ //#region src/js/tooltip.d.ts
2
+ declare function setDelay(value: number): void;
3
+ //#endregion
4
+ export { setDelay };
@@ -1,8 +1,9 @@
1
- import { attributable } from "./attributable.js";
2
- import { Floatable } from "./floatable.js";
1
+ import { attributable } from "./attributable.mjs";
2
+ import { Floatable } from "./floatable.mjs";
3
3
  import { on } from "@oscarpalmer/toretto/event";
4
4
  import { findAncestor } from "@oscarpalmer/toretto/find";
5
5
  import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
6
+ //#region src/js/tooltip.ts
6
7
  var Tooltip = class {
7
8
  attributes;
8
9
  floatable;
@@ -42,11 +43,11 @@ function closeTooltips(next) {
42
43
  for (const active of tooltips) {
43
44
  if (active === next) continue;
44
45
  if (active.timer != null) clearTimeout(active.timer);
45
- active.floatable.options.content.removeAttribute("oui-tooltip-content-active");
46
+ active.floatable?.options.content.removeAttribute("oui-tooltip-content-active");
46
47
  requestAnimationFrame(() => {
47
48
  active.timer = setTimeout(() => {
48
49
  TOOLTIPS_ACTIVE.delete(active);
49
- active.floatable.toggle(false);
50
+ active.floatable?.toggle(false);
50
51
  }, delay);
51
52
  });
52
53
  }
@@ -114,7 +115,7 @@ function onActivate(event) {
114
115
  onToggle(event, true);
115
116
  }
116
117
  function onClick(event) {
117
- if (findAncestor(event.target, SELECTOR_CONTENT) != null) event.stopPropagation();
118
+ if (findAncestor(event, SELECTOR_CONTENT) != null) event.stopPropagation();
118
119
  }
119
120
  function onDeactivate(event) {
120
121
  onToggle(event, false);
@@ -123,7 +124,7 @@ function onToggle(event, activate) {
123
124
  if (toggle != null) cancelAnimationFrame(toggle);
124
125
  toggle = requestAnimationFrame(() => {
125
126
  toggle = void 0;
126
- const element = findAncestor(event.target, SELECTOR_FULL);
127
+ const element = findAncestor(event, SELECTOR_FULL);
127
128
  const tooltip = TOOLTIPS_ALL.get(element);
128
129
  if (TOOLTIPS_ACTIVE.size > 0) closeTooltips(tooltip);
129
130
  if (tooltip == null || tooltip.floatable.options.content.hasAttribute("oui-tooltip-content-active") === activate) return;
@@ -153,22 +154,23 @@ function reset(anchor, attributes) {
153
154
  function setDelay(value) {
154
155
  delay = typeof value === "number" && value >= 0 ? value : delay;
155
156
  }
156
- var SELECTOR = "oui-tooltip";
157
- var ATTRIBUTE_CLASS = `${SELECTOR}-class`;
158
- var ATTRIBUTE_CONTENT = `${SELECTOR}-content`;
159
- var ATTRIBUTE_POSITION = `${SELECTOR}-position`;
160
- var SELECTOR_CONTENT = `[${ATTRIBUTE_CONTENT}]`;
161
- var SELECTOR_FULL = `[${SELECTOR}], [${ATTRIBUTE_CONTENT}]`;
162
- var EXPRESSION_WHITESPACE = /\s+/;
163
- var TOOLTIPS_ACTIVE = /* @__PURE__ */ new Set();
164
- var TOOLTIPS_ALL = /* @__PURE__ */ new WeakMap();
165
- var delay = 250;
166
- var index = 0;
167
- var toggle;
157
+ const SELECTOR = "oui-tooltip";
158
+ const ATTRIBUTE_CLASS = `${SELECTOR}-class`;
159
+ const ATTRIBUTE_CONTENT = `${SELECTOR}-content`;
160
+ const ATTRIBUTE_POSITION = `${SELECTOR}-position`;
161
+ const SELECTOR_CONTENT = `[${ATTRIBUTE_CONTENT}]`;
162
+ const SELECTOR_FULL = `[${SELECTOR}], [${ATTRIBUTE_CONTENT}]`;
163
+ const EXPRESSION_WHITESPACE = /\s+/;
164
+ const TOOLTIPS_ACTIVE = /* @__PURE__ */ new Set();
165
+ const TOOLTIPS_ALL = /* @__PURE__ */ new WeakMap();
166
+ let delay = 500;
167
+ let index = 0;
168
+ let toggle;
168
169
  attributable(SELECTOR, addTooltip, removeTooltip);
169
170
  on(document, "click", onClick, { capture: true });
170
171
  on(document, "focusin", onActivate);
171
172
  on(document, "focusout", onDeactivate);
172
173
  on(document, "mousemove", onActivate);
173
174
  on(document, "touchstart", onActivate);
175
+ //#endregion
174
176
  export { setDelay };
package/package.json CHANGED
@@ -1,90 +1,85 @@
1
1
  {
2
+ "name": "@oscarpalmer/oui",
3
+ "version": "0.20.0",
4
+ "description": "Styles, components, and utilities for building websites and applications.",
5
+ "keywords": [
6
+ "css",
7
+ "design",
8
+ "framework",
9
+ "library",
10
+ "scss",
11
+ "style",
12
+ "stylesheet",
13
+ "utility"
14
+ ],
15
+ "license": "MIT",
2
16
  "author": {
3
17
  "name": "Oscar Palmér",
4
18
  "url": "https://oscarpalmer.se"
5
19
  },
6
- "dependencies": {
7
- "@oscarpalmer/atoms": "^0.124",
8
- "@oscarpalmer/toretto": "^0.34"
9
- },
10
- "description": "Styles, components, and utilities for building websites and applications.",
11
- "devDependencies": {
12
- "@types/node": "^25",
13
- "@vitest/coverage-istanbul": "^4",
14
- "autoprefixer": "^10.4",
15
- "jsdom": "^27.4",
16
- "oxfmt": "^0.21",
17
- "oxlint": "^1.36",
18
- "postcss-cli": "^11",
19
- "postcss-input-range": "^6",
20
- "postcss-scss": "^4",
21
- "rolldown": "1.0.0-beta.57",
22
- "sass": "^1.97",
23
- "stylelint": "^16.26",
24
- "stylelint-config-standard-scss": "^16",
25
- "tslib": "^2.8",
26
- "typescript": "^5.9",
27
- "vite": "8.0.0-beta.5",
28
- "vitest": "^4"
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/oscarpalmer/oui.git"
29
23
  },
24
+ "files": [
25
+ "dist",
26
+ "src"
27
+ ],
28
+ "type": "module",
29
+ "module": "dist/js/index.mjs",
30
+ "types": "dist/js/index.d.mts",
30
31
  "exports": {
31
32
  ".": {
32
- "types": "./types/index.d.ts",
33
- "default": "./dist/js/index.js"
33
+ "types": "./dist/js/index.d.mts",
34
+ "default": "./dist/js/index.mjs"
34
35
  },
35
36
  "./focus-trap": {
36
- "types": "./types/focus-trap/standalone.d.ts",
37
- "default": "./dist/js/focus-trap/standalone.js"
37
+ "types": "./dist/js/focus-trap/standalone.d.mts",
38
+ "default": "./dist/js/focus-trap/standalone.mjs"
38
39
  },
39
40
  "./popover": {
40
- "types": "./types/popover.d.ts",
41
- "default": "./dist/js/popover.js"
41
+ "types": "./dist/js/popover.d.mts",
42
+ "default": "./dist/js/popover.mjs"
42
43
  },
43
44
  "./splitter": {
44
- "types": "./types/splitter.d.ts",
45
- "default": "./dist/js/splitter.js"
45
+ "types": "./dist/js/splitter.d.mts",
46
+ "default": "./dist/js/splitter.mjs"
46
47
  },
47
48
  "./tooltip": {
48
- "types": "./types/tooltip.d.ts",
49
- "default": "./dist/js/tooltip.js"
49
+ "types": "./dist/js/tooltip.d.mts",
50
+ "default": "./dist/js/tooltip.mjs"
50
51
  }
51
52
  },
52
- "files": [
53
- "dist",
54
- "src",
55
- "types"
56
- ],
57
- "keywords": [
58
- "css",
59
- "scss",
60
- "design",
61
- "framework",
62
- "library",
63
- "style",
64
- "stylesheet",
65
- "utility"
66
- ],
67
- "license": "MIT",
68
- "module": "dist/js/index.js",
69
- "name": "@oscarpalmer/oui",
70
- "repository": {
71
- "type": "git",
72
- "url": "git+https://github.com/oscarpalmer/oui.git"
73
- },
74
53
  "scripts": {
75
- "build": "npm run clean && npm run build:js && npm run build:css",
76
- "build:css": "npm run build:postcss && npx sass ./postcss:./dist/css --no-source-map",
77
- "build:postcss": "npx postcss ./src/css/*.scss -d ./postcss -u autoprefixer postcss-input-range --parser postcss-scss",
78
- "build:js": "npm run clean && npx vite build && npm run rolldown:build && npx tsc",
79
- "clean": "rm -rf ./dist && rm -rf ./types && rm -f ./tsconfig.tsbuildinfo",
80
- "rolldown:build": "npx rolldown -c",
81
- "rolldown:watch": "npx rolldown -c ./rolldown.config.js --watch",
82
- "test": "npx vitest --coverage",
83
- "watch:css": "npx sass ./postcss:./dist/css --no-source-map --watch",
84
- "watch:postcss": "npx postcss ./src/css/*.scss -d ./postcss -u autoprefixer postcss-input-range --parser postcss-scss --watch",
85
- "watch:js": "npx vite build --watch"
54
+ "build": "vp run build:js && vp run build:css",
55
+ "build:css": "vp run build:postcss && vpx sass ./postcss:./dist/css --no-source-map",
56
+ "build:postcss": "vpx postcss ./src/css/*.scss -d ./postcss -u autoprefixer postcss-input-range --parser postcss-scss",
57
+ "build:js": "vpx vp pack",
58
+ "test": "vpx vitest --coverage",
59
+ "tsdown:build": "vpx tsdown -c ./tsdown.config.ts",
60
+ "tsdown:watch": "vpx tsdown -c ./tsdown.config.ts --watch",
61
+ "watch:css": "vpx sass ./postcss:./dist/css --no-source-map --watch",
62
+ "watch:postcss": "vpx postcss ./src/css/*.scss -d ./postcss -u autoprefixer postcss-input-range --parser postcss-scss --watch",
63
+ "watch:js": "vpx vite build --watch"
86
64
  },
87
- "type": "module",
88
- "types": "types/index.d.ts",
89
- "version": "0.19.0"
65
+ "dependencies": {
66
+ "@oscarpalmer/atoms": "^0.170",
67
+ "@oscarpalmer/toretto": "^0.41"
68
+ },
69
+ "devDependencies": {
70
+ "@vitest/coverage-istanbul": "^4.1",
71
+ "autoprefixer": "^10.4",
72
+ "jsdom": "^29",
73
+ "postcss-cli": "^11",
74
+ "postcss-input-range": "^6",
75
+ "postcss-scss": "^4",
76
+ "sass": "^1.98",
77
+ "stylelint": "^17.6",
78
+ "stylelint-config-standard-scss": "^17",
79
+ "typescript": "^5.9",
80
+ "vite": "npm:@voidzero-dev/vite-plus-core@latest",
81
+ "vite-plus": "latest",
82
+ "vitest": "npm:@voidzero-dev/vite-plus-test@latest"
83
+ },
84
+ "packageManager": "npm@11.12.1"
90
85
  }
@@ -51,6 +51,36 @@
51
51
  border-radius: 0.5em;
52
52
  }
53
53
 
54
+ @mixin floatable() {
55
+ @include shadow-overlay;
56
+
57
+ --margin-left: 0;
58
+ --margin-top: 0;
59
+
60
+ margin: var(--margin-top, 0) 0 0 var(--margin-left, 0);
61
+ pointer-events: all !important;
62
+
63
+ &[position^='above'],
64
+ &[position^='top'] {
65
+ --margin-top: -0.5rem;
66
+ }
67
+
68
+ &[position^='below'],
69
+ &[position^='bottom'] {
70
+ --margin-top: 0.5rem;
71
+ }
72
+
73
+ &[position^='end'],
74
+ &[position^='right'] {
75
+ --margin-left: 0.5rem;
76
+ }
77
+
78
+ &[position^='left'],
79
+ &[position^='start'] {
80
+ --margin-left: -0.5rem;
81
+ }
82
+ }
83
+
54
84
  @mixin shadow($color: rgb(0 0 0 / 5%), $inset: transparent) {
55
85
  box-shadow:
56
86
  inset 0 1px 0 0 $inset,
@@ -83,7 +113,6 @@
83
113
  width: 1px !important;
84
114
  height: 1px !important;
85
115
  padding: 0 !important;
86
- clip: rect(1px, 1px 1px, 1px) !important;
87
116
  clip-path: inset(50%) !important;
88
117
  overflow: hidden !important;
89
118
  border: 0 !important;
@@ -1,13 +1,18 @@
1
1
  @use 'mixins.scss' as mixins;
2
2
 
3
3
  :where([oui-popover-content]) {
4
- @include mixins.shadow-overlay;
4
+ @include mixins.floatable;
5
5
 
6
6
  padding: 1rem;
7
+ overscroll-behavior: contain;
7
8
  background-color: var(--oui-absolute);
8
9
  border-radius: 0.5rem;
9
10
 
10
11
  &:focus {
11
12
  outline: none;
12
13
  }
14
+
15
+ * {
16
+ overscroll-behavior: contain;
17
+ }
13
18
  }
@@ -54,7 +54,7 @@
54
54
  /** Prevent text size inflation (e.g., after orientation change) [AB][RE][SE] */
55
55
  text-size-adjust: none;
56
56
  tab-size: 4;
57
- word-break: break-word;
57
+ overflow-wrap: break-word;
58
58
  }
59
59
 
60
60
  :where(body) {
@@ -104,7 +104,7 @@
104
104
  summary
105
105
  ) {
106
106
  /** Correct the inability to style clickable types in iOS [HR][RS][SE] */
107
- appearance: button;
107
+ appearance: auto;
108
108
  /** Ditto */
109
109
  cursor: pointer;
110
110
  }
@@ -171,7 +171,7 @@
171
171
  }
172
172
 
173
173
  :where(small, sub, sup) {
174
- font-size: 0.875rem;
174
+ font-size: 0.875em;
175
175
  }
176
176
 
177
177
  :where(sub, sup) {
@@ -271,7 +271,7 @@
271
271
 
272
272
  ::file-selector-button {
273
273
  /** Correct the inability to style upload buttons in iOS and Safari [RS][SE] */
274
- appearance: button;
274
+ appearance: auto;
275
275
  color: inherit;
276
276
  font: inherit;
277
277
  line-height: 1.25;
@@ -9,10 +9,10 @@
9
9
  :where(&_wrapper) {
10
10
  max-height: 32em;
11
11
  overflow: auto;
12
+ overscroll-behavior: contain;
12
13
  border: 1px solid var(--oui-gray-3);
13
14
  border-radius: 0.25em;
14
15
  position: relative;
15
- overscroll-behavior-y: none;
16
16
  }
17
17
 
18
18
  :where(& caption) {
@@ -29,7 +29,7 @@
29
29
  }
30
30
 
31
31
  :where([oui-tooltip-content]) {
32
- @include mixins.shadow-overlay;
32
+ @include mixins.floatable;
33
33
 
34
34
  max-width: 48ch;
35
35
  padding: 0.75em 1em;
@@ -39,6 +39,60 @@
39
39
  font-size: 0.875rem;
40
40
  transition: opacity 0.125s ease-in-out;
41
41
  transition-delay: 0s;
42
+
43
+ &::after {
44
+ content: '';
45
+ opacity: 0;
46
+ position: absolute;
47
+ }
48
+
49
+ &[position^='above'],
50
+ &[position^='below'],
51
+ &[position^='bottom'],
52
+ &[position^='top'] {
53
+ &::after {
54
+ width: 100%;
55
+ height: 0.5rem;
56
+ }
57
+ }
58
+
59
+ &[position^='above'],
60
+ &[position^='top'] {
61
+ &::after {
62
+ inset: 100% 0 0;
63
+ }
64
+ }
65
+
66
+ &[position^='below'],
67
+ &[position^='bottom'] {
68
+ &::after {
69
+ inset: -5rem 0 0;
70
+ }
71
+ }
72
+
73
+ &[position^='end'],
74
+ &[position^='left'],
75
+ &[position^='right'],
76
+ &[position^='start'] {
77
+ &::after {
78
+ width: 0.5rem;
79
+ height: 100%;
80
+ }
81
+ }
82
+
83
+ &[position^='end'],
84
+ &[position^='right'] {
85
+ &::after {
86
+ inset: 0 0 0 -0.5rem;
87
+ }
88
+ }
89
+
90
+ &[position^='left'],
91
+ &[position^='start'] {
92
+ &::after {
93
+ inset: 0 0 0 100%;
94
+ }
95
+ }
42
96
  }
43
97
 
44
98
  :where([oui-tooltip-content][oui-tooltip-content-active]) {
@@ -49,6 +49,10 @@ function handleAdded(
49
49
  if (element.hasAttribute(attribute)) {
50
50
  add(element);
51
51
  }
52
+
53
+ if (element.hasChildNodes()) {
54
+ handleAdded(attribute, element.childNodes, add);
55
+ }
52
56
  }
53
57
  }
54
58
 
@@ -58,6 +62,12 @@ function handleRemoved(nodes: Node[] | NodeList, remove: (element: HTMLElement)
58
62
  const {length} = elements;
59
63
 
60
64
  for (let index = 0; index < length; index += 1) {
61
- remove(elements[index]);
65
+ const element = elements[index];
66
+
67
+ remove(element);
68
+
69
+ if (element.hasChildNodes()) {
70
+ handleRemoved(element.childNodes, remove);
71
+ }
62
72
  }
63
73
  }