@oscarpalmer/oui 0.17.0 → 0.19.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 (72) hide show
  1. package/dist/css/badge.css +13 -13
  2. package/dist/css/button.css +9 -9
  3. package/dist/css/color.css +99 -99
  4. package/dist/css/content.css +10 -12
  5. package/dist/css/flex.css +39 -39
  6. package/dist/css/form.css +47 -60
  7. package/dist/css/message.css +10 -6
  8. package/dist/css/reset.css +178 -57
  9. package/dist/css/table.css +4 -4
  10. package/dist/css/tooltip.css +26 -1
  11. package/dist/js/attributable.full.js +36 -0
  12. package/dist/js/attributable.js +30 -45
  13. package/dist/js/floatable.full.js +398 -0
  14. package/dist/js/floatable.js +254 -169
  15. package/dist/js/focus-trap/embedded.full.js +408 -0
  16. package/dist/js/focus-trap/embedded.js +131 -131
  17. package/dist/js/focus-trap/standalone.full.js +447 -0
  18. package/dist/js/focus-trap/standalone.js +4 -4
  19. package/dist/js/index.js +3 -4
  20. package/dist/js/oui.full.js +1573 -0
  21. package/dist/js/popover.full.js +760 -0
  22. package/dist/js/popover.js +84 -163
  23. package/dist/js/splitter.full.js +769 -0
  24. package/dist/js/splitter.js +264 -246
  25. package/dist/js/tooltip.full.js +613 -0
  26. package/dist/js/tooltip.js +160 -151
  27. package/package.json +35 -63
  28. package/src/css/a11y.scss +1 -1
  29. package/src/css/badge.scss +23 -19
  30. package/src/css/button.scss +9 -9
  31. package/src/css/color.scss +99 -99
  32. package/src/css/content.scss +6 -9
  33. package/src/css/flex.scss +21 -20
  34. package/src/css/form.scss +47 -62
  35. package/src/css/message.scss +11 -12
  36. package/src/css/mixins.scss +16 -10
  37. package/src/css/popover.scss +2 -2
  38. package/src/css/reset.scss +181 -55
  39. package/src/css/splitter.scss +15 -13
  40. package/src/css/table.scss +11 -11
  41. package/src/css/tooltip.scss +31 -2
  42. package/src/js/attributable.ts +3 -10
  43. package/src/js/floatable.ts +370 -141
  44. package/src/js/focus-trap/embedded.ts +141 -74
  45. package/src/js/focus-trap/standalone.ts +4 -4
  46. package/src/js/index.ts +1 -0
  47. package/src/js/popover.ts +52 -122
  48. package/src/js/splitter.ts +248 -131
  49. package/src/js/tooltip.ts +143 -68
  50. package/types/floatable.d.ts +17 -10
  51. package/types/focus-trap/embedded.d.ts +18 -5
  52. package/types/index.d.ts +1 -0
  53. package/types/popover.d.ts +2 -0
  54. package/types/splitter.d.ts +13 -1
  55. package/types/tooltip.d.ts +2 -1
  56. package/dist/css/value.css +0 -1
  57. package/dist/js/attributable.cjs +0 -51
  58. package/dist/js/floatable.cjs +0 -176
  59. package/dist/js/focus-trap/embedded.cjs +0 -150
  60. package/dist/js/focus-trap/standalone.cjs +0 -8
  61. package/dist/js/index.cjs +0 -6
  62. package/dist/js/popover.cjs +0 -166
  63. package/dist/js/splitter.cjs +0 -272
  64. package/dist/js/tooltip.cjs +0 -166
  65. package/types/attributable.d.cts +0 -5
  66. package/types/floatable.d.cts +0 -20
  67. package/types/focus-trap/embedded.d.cts +0 -15
  68. package/types/focus-trap/standalone.d.cts +0 -3
  69. package/types/index.d.cts +0 -14
  70. package/types/popover.d.cts +0 -14
  71. package/types/splitter.d.cts +0 -10
  72. package/types/tooltip.d.cts +0 -3
@@ -1,176 +1,261 @@
1
- class Floatable {
2
- constructor(anchor, content, attribute, position, preferAbove) {
3
- this.anchor = anchor;
4
- this.content = content;
5
- this.attribute = attribute;
6
- this.position = position;
7
- this.preferAbove = preferAbove;
8
- setStyles(content);
9
- }
10
- activate;
11
- active = false;
12
- deactivate;
13
- frame;
14
- destroy() {
15
- this.activate = void 0;
16
- this.deactivate = void 0;
17
- this.frame = void 0;
18
- this.anchor = void 0;
19
- this.content = void 0;
20
- }
21
- }
22
- function activate(floatable, active, order, time) {
23
- stop(floatable);
24
- if (floatable.active) {
25
- return;
26
- }
27
- if (time == null || time === 0) {
28
- onActivate(floatable, active, order);
29
- } else {
30
- floatable.activate = +setTimeout(() => {
31
- onActivate(floatable, active, order);
32
- }, time);
33
- }
34
- }
35
- function deactivate(floatable, active, order, time) {
36
- stop(floatable);
37
- if (!floatable.active) {
38
- return;
39
- }
40
- if (time == null || time === 0) {
41
- onDeactivate(floatable, active, order);
42
- } else {
43
- floatable.deactivate = +setTimeout(() => {
44
- onDeactivate(floatable, active, order);
45
- }, time);
46
- }
1
+ import { on } from "@oscarpalmer/toretto/event";
2
+ import { findAncestor } from "@oscarpalmer/toretto/find";
3
+ var Floatable = class {
4
+ active = false;
5
+ disabled = false;
6
+ frame;
7
+ ignoreFocus = false;
8
+ constructor(options) {
9
+ this.options = options;
10
+ initialize(this);
11
+ }
12
+ destroy() {
13
+ stop(this);
14
+ const state = getState();
15
+ state?.active.delete(this);
16
+ state?.mapped.delete(this.options.anchor);
17
+ state?.mapped.delete(this.options.content);
18
+ this.options.anchor = void 0;
19
+ this.options.content = void 0;
20
+ }
21
+ disable() {
22
+ if (this.disabled) return;
23
+ this.disabled = true;
24
+ stop(this);
25
+ getState()?.active.delete(this);
26
+ }
27
+ enable() {
28
+ if (!this.disabled) return;
29
+ this.disabled = false;
30
+ initialize(this);
31
+ }
32
+ toggle(active, ignoreFocus) {
33
+ if (this.disabled || this.active === active) return;
34
+ const state = getState();
35
+ if (state == null) return;
36
+ this.ignoreFocus = !active && (ignoreFocus ?? false);
37
+ stop(this);
38
+ if (active) state.active.add(this);
39
+ else state.active.delete(this);
40
+ if (this.options.interactive) if (active) state.order.push(this);
41
+ else {
42
+ const index = state.order.indexOf(this);
43
+ if (index > -1) state.order.splice(index, 1);
44
+ }
45
+ if (active) activate(this);
46
+ else deactivate(this);
47
+ }
48
+ };
49
+ function activate(floatable) {
50
+ floatable.active = true;
51
+ document.body.append(floatable.options.content);
52
+ floatable.options.content.hidden = false;
53
+ updatePosition(floatable);
54
+ }
55
+ function closeAbove(element) {
56
+ const state = getState();
57
+ if (state == null) return;
58
+ const index = state.order.findIndex((floatable) => floatable.options.anchor === element || floatable.options.content === element);
59
+ if (index === -1 || index === state.order.length - 1) return;
60
+ while (index < state.order.length - 1) state.order.pop()?.toggle(false, true);
61
+ }
62
+ function closeAll() {
63
+ const state = getState();
64
+ const floatables = [...state?.active ?? []];
65
+ state?.active.clear();
66
+ for (const floatable of floatables) floatable.toggle(false, true);
67
+ }
68
+ function closeNonInteractive(state) {
69
+ for (const floatable of state.active) if (!floatable.options.interactive) floatable.toggle(false);
70
+ }
71
+ function deactivate(floatable) {
72
+ floatable.active = false;
73
+ floatable.options.content.hidden = true;
74
+ floatable.options.anchor.insertAdjacentElement(INSERT_AFTEREND, floatable.options.content);
75
+ floatable.options.onAfter?.(false);
76
+ }
77
+ function getState() {
78
+ return window._oscarpalmer_oui_floatable;
47
79
  }
48
80
  function getX(anchor, content, position) {
49
- if (position.endsWith("-end")) {
50
- const end = anchor.right - content.width;
51
- return end - margin < 0 ? margin : end;
52
- }
53
- if (position.endsWith("-start")) {
54
- const start = anchor.left;
55
- return start + content.width + margin > window.innerWidth ? window.innerWidth - content.width - margin : start;
56
- }
57
- if (position.startsWith("end")) {
58
- return anchor.right + margin;
59
- }
60
- if (position.startsWith("start")) {
61
- return anchor.left - content.width - margin;
62
- }
63
- if (position.startsWith("horizontal")) {
64
- if (anchor.right + content.width + margin <= window.innerWidth) {
65
- return anchor.right + margin;
66
- }
67
- return anchor.left - content.width - margin;
68
- }
69
- return anchor.left + (anchor.width - content.width) / 2;
81
+ if (position.endsWith(POSITION_SUFFIX_END)) {
82
+ const end = anchor.right - content.width;
83
+ return end < 0 ? 0 : end;
84
+ }
85
+ if (position.endsWith(POSITION_SUFFIX_START)) {
86
+ const start = anchor.left;
87
+ return start + content.width > window.innerWidth ? window.innerWidth - content.width : start;
88
+ }
89
+ if (position.startsWith(POSITION_END)) return anchor.right;
90
+ if (position.startsWith(POSITION_START)) return anchor.left - content.width;
91
+ if (position.startsWith(POSITION_HORIZONTAL)) {
92
+ if (anchor.right + content.width <= window.innerWidth) return anchor.right;
93
+ return anchor.left - content.width;
94
+ }
95
+ const left = anchor.left + (anchor.width - content.width) / 2;
96
+ return left < 0 ? 0 : left;
70
97
  }
71
98
  function getY(anchor, content, position, preferAbove) {
72
- if (position.startsWith("above")) {
73
- return anchor.top - content.height - margin;
74
- }
75
- if (position.startsWith("below")) {
76
- return anchor.bottom + margin;
77
- }
78
- if (position.endsWith("bottom")) {
79
- const bottom = anchor.bottom - content.height;
80
- return bottom + margin < 0 ? margin : bottom;
81
- }
82
- if (position.endsWith("top")) {
83
- const top = anchor.top;
84
- return top + content.height + margin > window.innerHeight ? window.innerHeight - content.height - margin : top;
85
- }
86
- if (position.startsWith("vertical")) {
87
- if (preferAbove && anchor.top - content.height - margin >= 0) {
88
- return anchor.top - content.height - margin;
89
- }
90
- if (anchor.bottom + content.height + margin <= document.body.clientHeight) {
91
- return anchor.bottom + margin;
92
- }
93
- return anchor.top - content.height - margin;
94
- }
95
- return anchor.top + (anchor.height - content.height) / 2;
96
- }
97
- function onActivate(floatable, active, order) {
98
- floatable.active = true;
99
- active.add(floatable);
100
- if (order != null) {
101
- order.push(floatable);
102
- }
103
- document.body.append(floatable.content);
104
- floatable.content.hidden = false;
105
- update(floatable);
106
- }
107
- function onDeactivate(floatable, active, order) {
108
- floatable.active = false;
109
- active.delete(floatable);
110
- const index = order?.indexOf(floatable) ?? -1;
111
- if (index > -1) {
112
- order?.splice(index, 1);
113
- }
114
- floatable.content.hidden = true;
115
- floatable.anchor.insertAdjacentElement("afterend", floatable.content);
116
- }
117
- function update(floatable) {
118
- let position = floatable.anchor.getAttribute(floatable.attribute)?.trim() ?? floatable.position;
119
- if (!positions.has(position)) {
120
- position = floatable.position;
121
- }
122
- function run() {
123
- const anchor = floatable.anchor.getBoundingClientRect();
124
- const content = floatable.content.getBoundingClientRect();
125
- const left = getX(anchor, content, position);
126
- const top = getY(anchor, content, position, floatable.preferAbove);
127
- floatable.content.style.inset = `${top}px auto auto ${left}px`;
128
- floatable.frame = requestAnimationFrame(run);
129
- }
130
- floatable.frame = requestAnimationFrame(run);
131
- }
132
- function setStyles(content) {
133
- content.style.position = "fixed";
134
- content.style.inset = "0 auto auto 0";
135
- content.style.zIndex = "10";
99
+ if (position.startsWith(POSITION_ABOVE)) return anchor.top - content.height;
100
+ if (position.startsWith(POSITION_BELOW)) return anchor.bottom;
101
+ if (position.endsWith(POSITION_BOTTOM)) {
102
+ const bottom = anchor.bottom - content.height;
103
+ return bottom < 0 ? 0 : bottom;
104
+ }
105
+ if (position.endsWith(POSITION_TOP)) {
106
+ const top = anchor.top;
107
+ return top + content.height > window.innerHeight ? window.innerHeight - content.height : top;
108
+ }
109
+ if (position.startsWith(POSITION_VERTICAL)) {
110
+ if (preferAbove && anchor.top - content.height >= 0) return anchor.top - content.height;
111
+ if (anchor.bottom + content.height <= document.body.clientHeight) return anchor.bottom;
112
+ return anchor.top - content.height;
113
+ }
114
+ return anchor.top + (anchor.height - content.height) / 2;
115
+ }
116
+ function initialize(floatable) {
117
+ const { anchor, content, interactive } = floatable.options;
118
+ if (interactive) {
119
+ anchor.setAttribute(ATTRIBUTE_ANCHOR, "");
120
+ content.setAttribute(ATTRIBUTE_CONTENT, "");
121
+ }
122
+ content.style.position = "fixed";
123
+ content.style.inset = "0 auto auto 0";
124
+ content.style.zIndex = "10";
125
+ const state = getState();
126
+ state?.mapped.set(anchor, floatable);
127
+ state?.mapped.set(content, floatable);
128
+ }
129
+ function isDisabled(element) {
130
+ return element.disabled || element.readOnly || element.getAttribute("aria-disabled") === "true";
131
+ }
132
+ function onClick(event) {
133
+ const related = findAncestor(event.target, SELECTOR_ALL);
134
+ if (!(related instanceof HTMLElement)) closeAll();
135
+ else if (related.hasAttribute(ATTRIBUTE_CONTENT)) closeAbove(related);
136
+ else if (!isDisabled(related)) toggle(related);
137
+ }
138
+ function onKeyDown(event) {
139
+ if (event.key !== "Escape") return;
140
+ const state = getState();
141
+ if (state == null || state.active.size === 0) return;
142
+ closeNonInteractive(state);
143
+ const related = findAncestor(event.target, SELECTOR_CONTENT);
144
+ if (!(related instanceof HTMLElement)) return;
145
+ closeAbove(related);
146
+ const floatable = state.mapped.get(related);
147
+ if (floatable != null) floatable.toggle(false);
136
148
  }
137
149
  function stop(floatable) {
138
- if (floatable.frame != null) {
139
- cancelAnimationFrame(floatable.frame);
140
- }
141
- if (floatable.activate != null) {
142
- clearTimeout(floatable.activate);
143
- }
144
- if (floatable.deactivate != null) {
145
- clearTimeout(floatable.deactivate);
146
- }
147
- floatable.activate = void 0;
148
- floatable.deactivate = void 0;
149
- floatable.frame = void 0;
150
- }
151
- const margin = Number.parseInt(getComputedStyle(document.documentElement).fontSize, 10) / 2;
152
- const positions = /* @__PURE__ */ new Set([
153
- "above",
154
- "above-end",
155
- "above-start",
156
- "below",
157
- "below-end",
158
- "below-start",
159
- "end",
160
- "end-bottom",
161
- "end-top",
162
- "horizontal",
163
- "horizontal-bottom",
164
- "horizontal-top",
165
- "start",
166
- "start-bottom",
167
- "start-top",
168
- "vertical",
169
- "vertical-end",
170
- "vertical-start"
150
+ if (floatable.frame != null) cancelAnimationFrame(floatable.frame);
151
+ floatable.frame = void 0;
152
+ }
153
+ function toggle(anchor) {
154
+ const floatable = getState()?.mapped.get(anchor);
155
+ if (floatable == null) {
156
+ closeAll();
157
+ return;
158
+ }
159
+ const active = Boolean(floatable.active);
160
+ const content = findAncestor(floatable.options.anchor, SELECTOR_CONTENT);
161
+ if (content == null) closeAll();
162
+ else closeAbove(content);
163
+ floatable.toggle(!active);
164
+ }
165
+ function updatePosition(floatable) {
166
+ let position = floatable.options.anchor.getAttribute(floatable.options.positionAttribute)?.trim() ?? floatable.options.defaultPosition;
167
+ if (!POSITIONS.has(position)) position = floatable.options.defaultPosition;
168
+ let previousAnchor;
169
+ let previousContent;
170
+ let calculated = false;
171
+ let runOnAfter = false;
172
+ function run() {
173
+ const anchor = floatable.options.anchor.getBoundingClientRect();
174
+ const content = floatable.options.content.getBoundingClientRect();
175
+ if (calculated) {
176
+ if (previousAnchor != null && previousContent != null) {
177
+ if (PROPERTIES.every((property) => anchor[property] === previousAnchor[property]) && PROPERTIES.every((property) => content[property] === previousContent[property])) {
178
+ floatable.frame = requestAnimationFrame(run);
179
+ return;
180
+ }
181
+ }
182
+ } else calculated = true;
183
+ update(anchor, content);
184
+ }
185
+ function update(anchor, content) {
186
+ previousAnchor = anchor;
187
+ previousContent = content;
188
+ const left = getX(anchor, content, position);
189
+ const top = getY(anchor, content, position, floatable.options.preferAbove);
190
+ if (top + content.height > window.innerHeight) floatable.options.content.style.height = `${window.innerHeight - top}px`;
191
+ else floatable.options.content.style.height = "";
192
+ if (left + content.width > window.innerWidth) floatable.options.content.style.width = `${window.innerWidth - left}px`;
193
+ else floatable.options.content.style.width = "";
194
+ floatable.options.content.style.transform = `translate3d(${left}px, ${top}px, 0)`;
195
+ floatable.frame = requestAnimationFrame(run);
196
+ if (!runOnAfter) {
197
+ runOnAfter = true;
198
+ floatable.options.onAfter?.(true);
199
+ }
200
+ }
201
+ floatable.frame = requestAnimationFrame(run);
202
+ }
203
+ var ATTRIBUTE_ANCHOR = "oui-floatable-anchor";
204
+ var ATTRIBUTE_CONTENT = "oui-floatable-content";
205
+ var INSERT_AFTEREND = "afterend";
206
+ var POSITION_ABOVE = "above";
207
+ var POSITION_BELOW = "below";
208
+ var POSITION_BOTTOM = "bottom";
209
+ var POSITION_END = "end";
210
+ var POSITION_HORIZONTAL = "horizontal";
211
+ var POSITION_START = "start";
212
+ var POSITION_SUFFIX_END = "-end";
213
+ var POSITION_SUFFIX_START = "-start";
214
+ var POSITION_TOP = "top";
215
+ var POSITION_VERTICAL = "vertical";
216
+ var POSITIONS = new Set([
217
+ "above",
218
+ "above-end",
219
+ "above-start",
220
+ "below",
221
+ "below-end",
222
+ "below-start",
223
+ "end",
224
+ "end-bottom",
225
+ "end-top",
226
+ "horizontal",
227
+ "horizontal-bottom",
228
+ "horizontal-top",
229
+ "start",
230
+ "start-bottom",
231
+ "start-top",
232
+ "vertical",
233
+ "vertical-end",
234
+ "vertical-start"
171
235
  ]);
172
- export {
173
- Floatable,
174
- activate,
175
- deactivate
176
- };
236
+ var PROPERTIES = [
237
+ "bottom",
238
+ "left",
239
+ "right",
240
+ "top"
241
+ ];
242
+ var SELECTOR_ALL = `[${ATTRIBUTE_ANCHOR}], [${ATTRIBUTE_CONTENT}]`;
243
+ var SELECTOR_CONTENT = `[${ATTRIBUTE_CONTENT}]`;
244
+ if (window._oscarpalmer_oui_floatable == null) {
245
+ Object.defineProperty(window, "_oscarpalmer_oui_floatable", {
246
+ enumerable: false,
247
+ value: {
248
+ active: /* @__PURE__ */ new Set(),
249
+ mapped: /* @__PURE__ */ new Map(),
250
+ order: []
251
+ },
252
+ writable: false
253
+ });
254
+ on(document, "keydown", (event) => {
255
+ onKeyDown(event);
256
+ });
257
+ on(document, "click", (event) => {
258
+ onClick(event);
259
+ });
260
+ }
261
+ export { Floatable, deactivate };