@mulsense/xnew 0.1.4 → 0.1.6

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.
@@ -1,5 +1,9 @@
1
1
  import { xnew } from '../core/xnew';
2
- export declare function AccordionFrame(frame: xnew.Unit, {}?: {}): {
2
+ export declare function AccordionFrame(frame: xnew.Unit, { open, duration, easing }?: {
3
+ open?: boolean;
4
+ duration?: number;
5
+ easing?: string;
6
+ }): {
3
7
  toggle(): void;
4
8
  open(): void;
5
9
  close(): void;
@@ -7,14 +11,10 @@ export declare function AccordionFrame(frame: xnew.Unit, {}?: {}): {
7
11
  export declare function AccordionHeader(header: xnew.Unit, {}?: {}): void;
8
12
  export declare function AccordionBullet(bullet: xnew.Unit, { type }?: {
9
13
  type?: string;
10
- }): {
11
- transition(status: number): void;
12
- } | undefined;
13
- export declare function AccordionContent(content: xnew.Unit, { open, duration, easing }?: {
14
- open?: boolean;
15
- duration?: number;
16
- easing?: string;
17
- }): {
18
- readonly status: number;
19
- transition(status: number): void;
14
+ }): void;
15
+ export declare function AccordionContent(content: xnew.Unit, {}?: {}): {
16
+ transition({ element, rate }: {
17
+ element: HTMLElement;
18
+ rate: number;
19
+ }): void;
20
20
  };
@@ -1,9 +1,15 @@
1
1
  import { xnew } from '../core/xnew';
2
- export declare function ModalFrame(frame: xnew.Unit, {}?: {}): {
3
- close(): void;
4
- };
5
- export declare function ModalContent(content: xnew.Unit, { duration, easing, background }?: {
2
+ export declare function ModalFrame(frame: xnew.Unit, { duration, easing }?: {
6
3
  duration?: number;
7
4
  easing?: string;
5
+ }): {
6
+ close(): void;
7
+ };
8
+ export declare function ModalContent(content: xnew.Unit, { background }?: {
8
9
  background?: string;
9
- }): void;
10
+ }): {
11
+ transition({ element, rate }: {
12
+ element: HTMLElement;
13
+ rate: number;
14
+ }): void;
15
+ };
@@ -1,12 +1,24 @@
1
1
  import { xnew } from '../core/xnew';
2
- export declare function TabFrame(frame: xnew.Unit, { select }?: {
3
- select?: number | undefined;
2
+ export declare function TabFrame(frame: xnew.Unit, { key }?: {
3
+ key?: string;
4
4
  }): void;
5
- export declare function TabButton(button: xnew.Unit, {}?: {}): {
6
- select(): void;
7
- deselect(): void;
5
+ export declare function TabButton(button: xnew.Unit, { key }?: {
6
+ key?: string;
7
+ }): {
8
+ select({ element }: {
9
+ element: HTMLElement;
10
+ }): void;
11
+ deselect({ element }: {
12
+ element: HTMLElement;
13
+ }): void;
8
14
  };
9
- export declare function TabContent(self: xnew.Unit, {}?: {}): {
10
- select(): void;
11
- deselect(): void;
15
+ export declare function TabContent(content: xnew.Unit, { key }?: {
16
+ key?: string;
17
+ }): {
18
+ select({ element }: {
19
+ element: HTMLElement;
20
+ }): void;
21
+ deselect({ element }: {
22
+ element: HTMLElement;
23
+ }): void;
12
24
  };
package/dist/xnew.d.ts CHANGED
@@ -117,28 +117,50 @@ declare function Screen(screen: xnew$1.Unit, { width, height, fit }?: {
117
117
 
118
118
  declare function InputFrame(frame: xnew$1.Unit, {}?: {}): void;
119
119
 
120
- declare function ModalFrame(frame: xnew$1.Unit, {}?: {}): {
121
- close(): void;
122
- };
123
- declare function ModalContent(content: xnew$1.Unit, { duration, easing, background }?: {
120
+ declare function ModalFrame(frame: xnew$1.Unit, { duration, easing }?: {
124
121
  duration?: number;
125
122
  easing?: string;
123
+ }): {
124
+ close(): void;
125
+ };
126
+ declare function ModalContent(content: xnew$1.Unit, { background }?: {
126
127
  background?: string;
127
- }): void;
128
+ }): {
129
+ transition({ element, rate }: {
130
+ element: HTMLElement;
131
+ rate: number;
132
+ }): void;
133
+ };
128
134
 
129
- declare function TabFrame(frame: xnew$1.Unit, { select }?: {
130
- select?: number | undefined;
135
+ declare function TabFrame(frame: xnew$1.Unit, { key }?: {
136
+ key?: string;
131
137
  }): void;
132
- declare function TabButton(button: xnew$1.Unit, {}?: {}): {
133
- select(): void;
134
- deselect(): void;
138
+ declare function TabButton(button: xnew$1.Unit, { key }?: {
139
+ key?: string;
140
+ }): {
141
+ select({ element }: {
142
+ element: HTMLElement;
143
+ }): void;
144
+ deselect({ element }: {
145
+ element: HTMLElement;
146
+ }): void;
135
147
  };
136
- declare function TabContent(self: xnew$1.Unit, {}?: {}): {
137
- select(): void;
138
- deselect(): void;
148
+ declare function TabContent(content: xnew$1.Unit, { key }?: {
149
+ key?: string;
150
+ }): {
151
+ select({ element }: {
152
+ element: HTMLElement;
153
+ }): void;
154
+ deselect({ element }: {
155
+ element: HTMLElement;
156
+ }): void;
139
157
  };
140
158
 
141
- declare function AccordionFrame(frame: xnew$1.Unit, {}?: {}): {
159
+ declare function AccordionFrame(frame: xnew$1.Unit, { open, duration, easing }?: {
160
+ open?: boolean;
161
+ duration?: number;
162
+ easing?: string;
163
+ }): {
142
164
  toggle(): void;
143
165
  open(): void;
144
166
  close(): void;
@@ -146,16 +168,12 @@ declare function AccordionFrame(frame: xnew$1.Unit, {}?: {}): {
146
168
  declare function AccordionHeader(header: xnew$1.Unit, {}?: {}): void;
147
169
  declare function AccordionBullet(bullet: xnew$1.Unit, { type }?: {
148
170
  type?: string;
149
- }): {
150
- transition(status: number): void;
151
- } | undefined;
152
- declare function AccordionContent(content: xnew$1.Unit, { open, duration, easing }?: {
153
- open?: boolean;
154
- duration?: number;
155
- easing?: string;
156
- }): {
157
- readonly status: number;
158
- transition(status: number): void;
171
+ }): void;
172
+ declare function AccordionContent(content: xnew$1.Unit, {}?: {}): {
173
+ transition({ element, rate }: {
174
+ element: HTMLElement;
175
+ rate: number;
176
+ }): void;
159
177
  };
160
178
 
161
179
  declare function DragFrame(frame: xnew$1.Unit, { x, y }?: {
package/dist/xnew.js CHANGED
@@ -502,7 +502,7 @@
502
502
  this._.systems[type].push(listener);
503
503
  }
504
504
  if (this._.listeners1.has(type, listener) === false) {
505
- const execute = Unit.wrap(this, listener);
505
+ const execute = Unit.wrap(Unit.current, listener);
506
506
  this._.listeners1.set(type, listener, [this.element, execute]);
507
507
  Unit.typeUnits.add(type, this);
508
508
  if (/^[A-Za-z]/.test(type)) {
@@ -577,9 +577,11 @@
577
577
  // event
578
578
  //----------------------------------------------------------------------------------------------------
579
579
  Unit.typeUnits = new MapSet();
580
- Unit.reset();
581
580
 
582
581
  const xnew$1 = function (...args) {
582
+ if (Unit.root === null) {
583
+ Unit.reset();
584
+ }
583
585
  let target;
584
586
  if (args[0] instanceof HTMLElement || args[0] instanceof SVGElement) {
585
587
  target = args.shift(); // an existing html element
@@ -990,7 +992,9 @@
990
992
 
991
993
  function InputFrame(frame, {} = {}) {
992
994
  xnew$1.nest('<div>');
993
- xnew$1.capture((unit) => unit.element.tagName.toLowerCase() === 'input', (unit) => {
995
+ xnew$1.capture((unit) => {
996
+ return unit.element.tagName.toLowerCase() === 'input';
997
+ }, (unit) => {
994
998
  const element = unit.element;
995
999
  xnew$1.listener(element).on('input', (event) => {
996
1000
  frame.emit('-input', { event });
@@ -1004,177 +1008,171 @@
1004
1008
  });
1005
1009
  }
1006
1010
 
1007
- function ModalFrame(frame, {} = {}) {
1008
- xnew$1.context('xnew.modalframe', frame);
1009
- xnew$1.nest('<div style="position: fixed; inset: 0; z-index: 1000;">');
1010
- xnew$1.capture((unit) => unit.components.includes(ModalContent), (unit) => {
1011
+ function ModalFrame(frame, { duration = 200, easing = 'ease' } = {}) {
1012
+ const internal = xnew$1((internal) => {
1013
+ return {};
1011
1014
  });
1012
- xnew$1().on('click', (event) => frame === null || frame === void 0 ? void 0 : frame.close());
1015
+ xnew$1.context('xnew.modalframe', internal);
1016
+ xnew$1.nest('<div style="position: fixed; inset: 0; z-index: 1000;">');
1017
+ xnew$1().on('click', (event) => frame.close());
1018
+ xnew$1.transition((x) => internal.emit('-transition', { rate: x }), duration, easing);
1013
1019
  return {
1014
1020
  close() {
1015
- frame.emit('-close');
1021
+ xnew$1.transition((x) => internal.emit('-transition', { rate: 1.0 - x }), duration, easing)
1022
+ .next(() => frame.finalize());
1016
1023
  }
1017
1024
  };
1018
1025
  }
1019
- function ModalContent(content, { duration = 200, easing = 'ease', background = 'rgba(0, 0, 0, 0.1)' } = {}) {
1020
- const frame = xnew$1.context('xnew.modalframe');
1021
- const div = xnew$1.nest('<div style="width: 100%; height: 100%; opacity: 0;">');
1022
- div.style.background = background;
1026
+ function ModalContent(content, { background = 'rgba(0, 0, 0, 0.1)' } = {}) {
1027
+ const internal = xnew$1.context('xnew.modalframe');
1028
+ xnew$1.nest(`<div style="width: 100%; height: 100%; opacity: 0; background: ${background}">`);
1023
1029
  xnew$1.nest('<div style="position: absolute; inset: 0; margin: auto; width: max-content; height: max-content;">');
1024
1030
  xnew$1().on('click', (event) => event.stopPropagation());
1025
- xnew$1.timeout(() => frame.emit('-open'));
1026
- frame.on('-open', () => {
1027
- xnew$1.transition((x) => {
1028
- div.style.opacity = x.toString();
1029
- }, duration, easing);
1030
- });
1031
- frame.on('-close', () => {
1032
- xnew$1.transition((x) => {
1033
- div.style.opacity = (1.0 - x).toString();
1034
- }, duration, easing).next(() => frame.finalize());
1031
+ internal.on('-transition', ({ rate }) => {
1032
+ content.transition({ element: content.element, rate });
1035
1033
  });
1034
+ return {
1035
+ transition({ element, rate }) {
1036
+ const wrapper = element.parentElement;
1037
+ wrapper.style.opacity = rate.toString();
1038
+ }
1039
+ };
1036
1040
  }
1037
1041
 
1038
- function TabFrame(frame, { select = 0 } = {}) {
1039
- xnew$1.context('xnew.tabframe', frame);
1040
- const buttons = [];
1041
- const contents = [];
1042
- xnew$1.capture((unit) => unit.components.includes(TabButton), (unit) => {
1043
- buttons.push(unit);
1044
- });
1045
- xnew$1.capture((unit) => unit.components.includes(TabContent), (unit) => {
1046
- contents.push(unit);
1042
+ function TabFrame(frame, { key } = {}) {
1043
+ const internal = xnew$1((internal) => {
1044
+ const buttons = new Map();
1045
+ const contents = new Map();
1046
+ return { frame, buttons, contents };
1047
1047
  });
1048
- frame.on('-click', ({ unit }) => execute(buttons.indexOf(unit)));
1049
- const timeout = xnew$1.timeout(() => execute(select));
1050
- function execute(index) {
1051
- timeout.clear();
1052
- const button = buttons[index];
1053
- const content = contents[index];
1054
- buttons.filter((item) => item !== button).forEach((item) => item.deselect());
1055
- contents.filter((item) => item !== content).forEach((item) => item.deselect());
1056
- button.select();
1057
- content.select();
1058
- }
1048
+ xnew$1.context('xnew.tabframe', internal);
1049
+ xnew$1.timeout(() => internal.emit('-select', { key: key !== null && key !== void 0 ? key : [...internal.buttons.keys()][0] }));
1059
1050
  }
1060
- function TabButton(button, {} = {}) {
1061
- const frame = xnew$1.context('xnew.tabframe');
1062
- xnew$1.nest('<div>');
1063
- button.on('click', () => frame.emit('-click', { unit: button }));
1051
+ function TabButton(button, { key } = {}) {
1052
+ const internal = xnew$1.context('xnew.tabframe');
1053
+ const div = xnew$1.nest('<div>');
1054
+ key = key !== null && key !== void 0 ? key : (internal.buttons.size).toString();
1055
+ internal.buttons.set(key, button);
1056
+ button.on('click', () => {
1057
+ internal.emit('-select', { key });
1058
+ });
1059
+ internal.on('-select', ({ key }) => {
1060
+ const select = internal.buttons.get(key);
1061
+ if (select === button) {
1062
+ button.select({ element: div });
1063
+ }
1064
+ else {
1065
+ button.deselect({ element: div });
1066
+ }
1067
+ });
1064
1068
  return {
1065
- select() {
1066
- Object.assign(button.element.style, { opacity: 1.0, cursor: 'text' });
1069
+ select({ element }) {
1070
+ Object.assign(element.style, { opacity: 1.0, cursor: 'text' });
1067
1071
  },
1068
- deselect() {
1069
- Object.assign(button.element.style, { opacity: 0.6, cursor: 'pointer' });
1072
+ deselect({ element }) {
1073
+ Object.assign(element.style, { opacity: 0.6, cursor: 'pointer' });
1070
1074
  }
1071
1075
  };
1072
1076
  }
1073
- function TabContent(self, {} = {}) {
1074
- xnew$1.context('xnew.tabframe');
1075
- xnew$1.nest('<div>');
1077
+ function TabContent(content, { key } = {}) {
1078
+ const internal = xnew$1.context('xnew.tabframe');
1079
+ const div = xnew$1.nest('<div style="display: none;">');
1080
+ key = key !== null && key !== void 0 ? key : (internal.contents.size).toString();
1081
+ internal.contents.set(key, content);
1082
+ internal.on('-select', ({ key }) => {
1083
+ const select = internal.contents.get(key);
1084
+ if (select === content) {
1085
+ content.select({ element: div });
1086
+ }
1087
+ else {
1088
+ content.deselect({ element: div });
1089
+ }
1090
+ });
1076
1091
  return {
1077
- select() {
1078
- Object.assign(self.element.style, { display: 'block' });
1092
+ select({ element }) {
1093
+ Object.assign(element.style, { display: 'block' });
1079
1094
  },
1080
- deselect() {
1081
- Object.assign(self.element.style, { display: 'none' });
1095
+ deselect({ element }) {
1096
+ Object.assign(element.style, { display: 'none' });
1082
1097
  }
1083
1098
  };
1084
1099
  }
1085
1100
 
1086
- function AccordionFrame(frame, {} = {}) {
1087
- xnew$1.context('xnew.accordionframe', frame);
1088
- let content = null;
1089
- xnew$1.capture((unit) => unit.components.includes(AccordionContent), (unit) => {
1090
- content = unit;
1101
+ function AccordionFrame(frame, { open = false, duration = 200, easing = 'ease' } = {}) {
1102
+ const internal = xnew$1((internal) => {
1103
+ return { frame, open, rate: 0.0, };
1091
1104
  });
1105
+ xnew$1.context('xnew.accordionframe', internal);
1106
+ internal.on('-transition', ({ rate }) => internal.rate = rate);
1107
+ internal.emit('-transition', { rate: open ? 1.0 : 0.0 });
1092
1108
  return {
1093
1109
  toggle() {
1094
- if ((content === null || content === void 0 ? void 0 : content.status) === 1.0) {
1095
- frame.emit('-close');
1110
+ if (internal.rate === 1.0) {
1111
+ frame.close();
1096
1112
  }
1097
- else if ((content === null || content === void 0 ? void 0 : content.status) === 0.0) {
1098
- frame.emit('-open');
1113
+ else if (internal.rate === 0.0) {
1114
+ frame.open();
1099
1115
  }
1100
1116
  },
1101
1117
  open() {
1102
- if ((content === null || content === void 0 ? void 0 : content.status) === 0.0) {
1103
- frame.emit('-open');
1118
+ if (internal.rate === 0.0) {
1119
+ xnew$1.transition((x) => internal.emit('-transition', { rate: x }), duration, easing);
1104
1120
  }
1105
1121
  },
1106
1122
  close() {
1107
- if ((content === null || content === void 0 ? void 0 : content.status) === 1.0) {
1108
- frame.emit('-close');
1123
+ if (internal.rate === 1.0) {
1124
+ xnew$1.transition((x) => internal.emit('-transition', { rate: 1.0 - x }), duration, easing);
1109
1125
  }
1110
1126
  }
1111
1127
  };
1112
1128
  }
1113
1129
  function AccordionHeader(header, {} = {}) {
1114
- const frame = xnew$1.context('xnew.accordionframe');
1130
+ const internal = xnew$1.context('xnew.accordionframe');
1115
1131
  xnew$1.nest('<button style="display: flex; align-items: center; margin: 0; padding: 0; width: 100%; text-align: left; border: none; font: inherit; color: inherit; background: none; cursor: pointer;">');
1116
- header.on('click', () => frame.toggle());
1132
+ header.on('click', () => internal.frame.toggle());
1117
1133
  }
1118
1134
  function AccordionBullet(bullet, { type = 'arrow' } = {}) {
1119
- const frame = xnew$1.context('xnew.accordionframe');
1120
- xnew$1.nest('<div style="display:inline-block; position: relative; width: 0.5em; margin: 0 0.3em;">');
1121
- frame.on('-transition', ({ status }) => { var _a; return (_a = bullet.transition) === null || _a === void 0 ? void 0 : _a.call(bullet, status); });
1135
+ const internal = xnew$1.context('xnew.accordionframe');
1136
+ xnew$1.nest('<div style="display:inline-block; position: relative; width: 0.55em; margin: 0 0.3em;">');
1122
1137
  if (type === 'arrow') {
1123
- const arrow = xnew$1(`<div style="width: 100%; height: 0.5em; border-right: 0.12em solid currentColor; border-bottom: 0.12em solid currentColor; box-sizing: border-box; transform-origin: center center;">`);
1124
- return {
1125
- transition(status) {
1126
- arrow.element.style.transform = `rotate(${status * 90 - 45}deg)`;
1127
- }
1128
- };
1138
+ const arrow = xnew$1(`<div style="width: 100%; height: 0.55em; border-right: 0.12em solid currentColor; border-bottom: 0.12em solid currentColor; box-sizing: border-box; transform-origin: center;">`);
1139
+ arrow.element.style.transform = `rotate(${internal.rate * 90 - 45}deg)`;
1140
+ internal.on('-transition', ({ rate }) => {
1141
+ arrow.element.style.transform = `rotate(${rate * 90 - 45}deg)`;
1142
+ });
1129
1143
  }
1130
1144
  else if (type === 'plusminus') {
1131
- xnew$1(`<div style="position: absolute; width: 100%; border-top: 0.06em solid currentColor; border-bottom: 0.06em solid currentColor; box-sizing: border-box; transform-origin: center center;">`);
1132
- const line2 = xnew$1(`<div style="position: absolute; width: 100%; border-top: 0.06em solid currentColor; border-bottom: 0.06em solid currentColor; box-sizing: border-box; transform-origin: center center;">`);
1145
+ const line1 = xnew$1(`<div style="position: absolute; width: 100%; border-top: 0.06em solid currentColor; border-bottom: 0.06em solid currentColor; box-sizing: border-box; transform-origin: center;">`);
1146
+ const line2 = xnew$1(`<div style="position: absolute; width: 100%; border-top: 0.06em solid currentColor; border-bottom: 0.06em solid currentColor; box-sizing: border-box; transform-origin: center;">`);
1133
1147
  line2.element.style.transform = `rotate(90deg)`;
1134
- return {
1135
- transition(status) {
1136
- line2.element.style.opacity = `${1.0 - status}`;
1137
- }
1138
- };
1148
+ line2.element.style.opacity = `${1.0 - internal.rate}`;
1149
+ internal.on('-transition', ({ rate }) => {
1150
+ line1.element.style.transform = `rotate(${90 + rate * 90}deg)`;
1151
+ line2.element.style.transform = `rotate(${rate * 180}deg)`;
1152
+ });
1139
1153
  }
1140
1154
  }
1141
- function AccordionContent(content, { open = false, duration = 200, easing = 'ease' } = {}) {
1142
- const frame = xnew$1.context('xnew.accordionframe');
1143
- const outer = xnew$1.nest('<div>');
1144
- const inner = xnew$1.nest('<div style="padding: 0; display: flex; flex-direction: column; box-sizing: border-box;">');
1145
- let status = open ? 1.0 : 0.0;
1146
- outer.style.display = status ? 'block' : 'none';
1147
- frame.emit('-transition', { status });
1148
- frame.on('-open', () => {
1149
- xnew$1.transition((x) => {
1150
- status = x;
1151
- frame.emit('-transition', { status });
1152
- content.transition(status);
1153
- }, duration, easing);
1154
- });
1155
- frame.on('-close', () => {
1156
- xnew$1.transition((x) => {
1157
- status = 1.0 - x;
1158
- frame.emit('-transition', { status });
1159
- content.transition(status);
1160
- }, duration, easing);
1155
+ function AccordionContent(content, {} = {}) {
1156
+ const internal = xnew$1.context('xnew.accordionframe');
1157
+ xnew$1.nest(`<div style="display: ${internal.open ? 'block' : 'none'};">`);
1158
+ xnew$1.nest('<div style="padding: 0; display: flex; flex-direction: column; box-sizing: border-box;">');
1159
+ internal.on('-transition', ({ rate }) => {
1160
+ content.transition({ element: content.element, rate });
1161
1161
  });
1162
1162
  return {
1163
- get status() {
1164
- return status;
1165
- },
1166
- transition(status) {
1167
- outer.style.display = 'block';
1168
- if (status === 0.0) {
1169
- outer.style.display = 'none';
1163
+ transition({ element, rate }) {
1164
+ const wrapper = element.parentElement;
1165
+ wrapper.style.display = 'block';
1166
+ if (rate === 0.0) {
1167
+ wrapper.style.display = 'none';
1170
1168
  }
1171
- else if (status < 1.0) {
1172
- Object.assign(outer.style, { height: inner.offsetHeight * status + 'px', overflow: 'hidden', opacity: status });
1169
+ else if (rate < 1.0) {
1170
+ Object.assign(wrapper.style, { height: element.offsetHeight * rate + 'px', overflow: 'hidden', opacity: rate });
1173
1171
  }
1174
1172
  else {
1175
- Object.assign(outer.style, { height: 'auto', overflow: 'visible', opacity: 1.0 });
1173
+ Object.assign(wrapper.style, { height: 'auto', overflow: 'visible', opacity: 1.0 });
1176
1174
  }
1177
- },
1175
+ }
1178
1176
  };
1179
1177
  }
1180
1178
 
package/dist/xnew.mjs CHANGED
@@ -496,7 +496,7 @@ class Unit {
496
496
  this._.systems[type].push(listener);
497
497
  }
498
498
  if (this._.listeners1.has(type, listener) === false) {
499
- const execute = Unit.wrap(this, listener);
499
+ const execute = Unit.wrap(Unit.current, listener);
500
500
  this._.listeners1.set(type, listener, [this.element, execute]);
501
501
  Unit.typeUnits.add(type, this);
502
502
  if (/^[A-Za-z]/.test(type)) {
@@ -571,9 +571,11 @@ Unit.componentUnits = new MapSet();
571
571
  // event
572
572
  //----------------------------------------------------------------------------------------------------
573
573
  Unit.typeUnits = new MapSet();
574
- Unit.reset();
575
574
 
576
575
  const xnew$1 = function (...args) {
576
+ if (Unit.root === null) {
577
+ Unit.reset();
578
+ }
577
579
  let target;
578
580
  if (args[0] instanceof HTMLElement || args[0] instanceof SVGElement) {
579
581
  target = args.shift(); // an existing html element
@@ -984,7 +986,9 @@ function Screen(screen, { width = 640, height = 480, fit = 'contain' } = {}) {
984
986
 
985
987
  function InputFrame(frame, {} = {}) {
986
988
  xnew$1.nest('<div>');
987
- xnew$1.capture((unit) => unit.element.tagName.toLowerCase() === 'input', (unit) => {
989
+ xnew$1.capture((unit) => {
990
+ return unit.element.tagName.toLowerCase() === 'input';
991
+ }, (unit) => {
988
992
  const element = unit.element;
989
993
  xnew$1.listener(element).on('input', (event) => {
990
994
  frame.emit('-input', { event });
@@ -998,177 +1002,171 @@ function InputFrame(frame, {} = {}) {
998
1002
  });
999
1003
  }
1000
1004
 
1001
- function ModalFrame(frame, {} = {}) {
1002
- xnew$1.context('xnew.modalframe', frame);
1003
- xnew$1.nest('<div style="position: fixed; inset: 0; z-index: 1000;">');
1004
- xnew$1.capture((unit) => unit.components.includes(ModalContent), (unit) => {
1005
+ function ModalFrame(frame, { duration = 200, easing = 'ease' } = {}) {
1006
+ const internal = xnew$1((internal) => {
1007
+ return {};
1005
1008
  });
1006
- xnew$1().on('click', (event) => frame === null || frame === void 0 ? void 0 : frame.close());
1009
+ xnew$1.context('xnew.modalframe', internal);
1010
+ xnew$1.nest('<div style="position: fixed; inset: 0; z-index: 1000;">');
1011
+ xnew$1().on('click', (event) => frame.close());
1012
+ xnew$1.transition((x) => internal.emit('-transition', { rate: x }), duration, easing);
1007
1013
  return {
1008
1014
  close() {
1009
- frame.emit('-close');
1015
+ xnew$1.transition((x) => internal.emit('-transition', { rate: 1.0 - x }), duration, easing)
1016
+ .next(() => frame.finalize());
1010
1017
  }
1011
1018
  };
1012
1019
  }
1013
- function ModalContent(content, { duration = 200, easing = 'ease', background = 'rgba(0, 0, 0, 0.1)' } = {}) {
1014
- const frame = xnew$1.context('xnew.modalframe');
1015
- const div = xnew$1.nest('<div style="width: 100%; height: 100%; opacity: 0;">');
1016
- div.style.background = background;
1020
+ function ModalContent(content, { background = 'rgba(0, 0, 0, 0.1)' } = {}) {
1021
+ const internal = xnew$1.context('xnew.modalframe');
1022
+ xnew$1.nest(`<div style="width: 100%; height: 100%; opacity: 0; background: ${background}">`);
1017
1023
  xnew$1.nest('<div style="position: absolute; inset: 0; margin: auto; width: max-content; height: max-content;">');
1018
1024
  xnew$1().on('click', (event) => event.stopPropagation());
1019
- xnew$1.timeout(() => frame.emit('-open'));
1020
- frame.on('-open', () => {
1021
- xnew$1.transition((x) => {
1022
- div.style.opacity = x.toString();
1023
- }, duration, easing);
1024
- });
1025
- frame.on('-close', () => {
1026
- xnew$1.transition((x) => {
1027
- div.style.opacity = (1.0 - x).toString();
1028
- }, duration, easing).next(() => frame.finalize());
1025
+ internal.on('-transition', ({ rate }) => {
1026
+ content.transition({ element: content.element, rate });
1029
1027
  });
1028
+ return {
1029
+ transition({ element, rate }) {
1030
+ const wrapper = element.parentElement;
1031
+ wrapper.style.opacity = rate.toString();
1032
+ }
1033
+ };
1030
1034
  }
1031
1035
 
1032
- function TabFrame(frame, { select = 0 } = {}) {
1033
- xnew$1.context('xnew.tabframe', frame);
1034
- const buttons = [];
1035
- const contents = [];
1036
- xnew$1.capture((unit) => unit.components.includes(TabButton), (unit) => {
1037
- buttons.push(unit);
1038
- });
1039
- xnew$1.capture((unit) => unit.components.includes(TabContent), (unit) => {
1040
- contents.push(unit);
1036
+ function TabFrame(frame, { key } = {}) {
1037
+ const internal = xnew$1((internal) => {
1038
+ const buttons = new Map();
1039
+ const contents = new Map();
1040
+ return { frame, buttons, contents };
1041
1041
  });
1042
- frame.on('-click', ({ unit }) => execute(buttons.indexOf(unit)));
1043
- const timeout = xnew$1.timeout(() => execute(select));
1044
- function execute(index) {
1045
- timeout.clear();
1046
- const button = buttons[index];
1047
- const content = contents[index];
1048
- buttons.filter((item) => item !== button).forEach((item) => item.deselect());
1049
- contents.filter((item) => item !== content).forEach((item) => item.deselect());
1050
- button.select();
1051
- content.select();
1052
- }
1042
+ xnew$1.context('xnew.tabframe', internal);
1043
+ xnew$1.timeout(() => internal.emit('-select', { key: key !== null && key !== void 0 ? key : [...internal.buttons.keys()][0] }));
1053
1044
  }
1054
- function TabButton(button, {} = {}) {
1055
- const frame = xnew$1.context('xnew.tabframe');
1056
- xnew$1.nest('<div>');
1057
- button.on('click', () => frame.emit('-click', { unit: button }));
1045
+ function TabButton(button, { key } = {}) {
1046
+ const internal = xnew$1.context('xnew.tabframe');
1047
+ const div = xnew$1.nest('<div>');
1048
+ key = key !== null && key !== void 0 ? key : (internal.buttons.size).toString();
1049
+ internal.buttons.set(key, button);
1050
+ button.on('click', () => {
1051
+ internal.emit('-select', { key });
1052
+ });
1053
+ internal.on('-select', ({ key }) => {
1054
+ const select = internal.buttons.get(key);
1055
+ if (select === button) {
1056
+ button.select({ element: div });
1057
+ }
1058
+ else {
1059
+ button.deselect({ element: div });
1060
+ }
1061
+ });
1058
1062
  return {
1059
- select() {
1060
- Object.assign(button.element.style, { opacity: 1.0, cursor: 'text' });
1063
+ select({ element }) {
1064
+ Object.assign(element.style, { opacity: 1.0, cursor: 'text' });
1061
1065
  },
1062
- deselect() {
1063
- Object.assign(button.element.style, { opacity: 0.6, cursor: 'pointer' });
1066
+ deselect({ element }) {
1067
+ Object.assign(element.style, { opacity: 0.6, cursor: 'pointer' });
1064
1068
  }
1065
1069
  };
1066
1070
  }
1067
- function TabContent(self, {} = {}) {
1068
- xnew$1.context('xnew.tabframe');
1069
- xnew$1.nest('<div>');
1071
+ function TabContent(content, { key } = {}) {
1072
+ const internal = xnew$1.context('xnew.tabframe');
1073
+ const div = xnew$1.nest('<div style="display: none;">');
1074
+ key = key !== null && key !== void 0 ? key : (internal.contents.size).toString();
1075
+ internal.contents.set(key, content);
1076
+ internal.on('-select', ({ key }) => {
1077
+ const select = internal.contents.get(key);
1078
+ if (select === content) {
1079
+ content.select({ element: div });
1080
+ }
1081
+ else {
1082
+ content.deselect({ element: div });
1083
+ }
1084
+ });
1070
1085
  return {
1071
- select() {
1072
- Object.assign(self.element.style, { display: 'block' });
1086
+ select({ element }) {
1087
+ Object.assign(element.style, { display: 'block' });
1073
1088
  },
1074
- deselect() {
1075
- Object.assign(self.element.style, { display: 'none' });
1089
+ deselect({ element }) {
1090
+ Object.assign(element.style, { display: 'none' });
1076
1091
  }
1077
1092
  };
1078
1093
  }
1079
1094
 
1080
- function AccordionFrame(frame, {} = {}) {
1081
- xnew$1.context('xnew.accordionframe', frame);
1082
- let content = null;
1083
- xnew$1.capture((unit) => unit.components.includes(AccordionContent), (unit) => {
1084
- content = unit;
1095
+ function AccordionFrame(frame, { open = false, duration = 200, easing = 'ease' } = {}) {
1096
+ const internal = xnew$1((internal) => {
1097
+ return { frame, open, rate: 0.0, };
1085
1098
  });
1099
+ xnew$1.context('xnew.accordionframe', internal);
1100
+ internal.on('-transition', ({ rate }) => internal.rate = rate);
1101
+ internal.emit('-transition', { rate: open ? 1.0 : 0.0 });
1086
1102
  return {
1087
1103
  toggle() {
1088
- if ((content === null || content === void 0 ? void 0 : content.status) === 1.0) {
1089
- frame.emit('-close');
1104
+ if (internal.rate === 1.0) {
1105
+ frame.close();
1090
1106
  }
1091
- else if ((content === null || content === void 0 ? void 0 : content.status) === 0.0) {
1092
- frame.emit('-open');
1107
+ else if (internal.rate === 0.0) {
1108
+ frame.open();
1093
1109
  }
1094
1110
  },
1095
1111
  open() {
1096
- if ((content === null || content === void 0 ? void 0 : content.status) === 0.0) {
1097
- frame.emit('-open');
1112
+ if (internal.rate === 0.0) {
1113
+ xnew$1.transition((x) => internal.emit('-transition', { rate: x }), duration, easing);
1098
1114
  }
1099
1115
  },
1100
1116
  close() {
1101
- if ((content === null || content === void 0 ? void 0 : content.status) === 1.0) {
1102
- frame.emit('-close');
1117
+ if (internal.rate === 1.0) {
1118
+ xnew$1.transition((x) => internal.emit('-transition', { rate: 1.0 - x }), duration, easing);
1103
1119
  }
1104
1120
  }
1105
1121
  };
1106
1122
  }
1107
1123
  function AccordionHeader(header, {} = {}) {
1108
- const frame = xnew$1.context('xnew.accordionframe');
1124
+ const internal = xnew$1.context('xnew.accordionframe');
1109
1125
  xnew$1.nest('<button style="display: flex; align-items: center; margin: 0; padding: 0; width: 100%; text-align: left; border: none; font: inherit; color: inherit; background: none; cursor: pointer;">');
1110
- header.on('click', () => frame.toggle());
1126
+ header.on('click', () => internal.frame.toggle());
1111
1127
  }
1112
1128
  function AccordionBullet(bullet, { type = 'arrow' } = {}) {
1113
- const frame = xnew$1.context('xnew.accordionframe');
1114
- xnew$1.nest('<div style="display:inline-block; position: relative; width: 0.5em; margin: 0 0.3em;">');
1115
- frame.on('-transition', ({ status }) => { var _a; return (_a = bullet.transition) === null || _a === void 0 ? void 0 : _a.call(bullet, status); });
1129
+ const internal = xnew$1.context('xnew.accordionframe');
1130
+ xnew$1.nest('<div style="display:inline-block; position: relative; width: 0.55em; margin: 0 0.3em;">');
1116
1131
  if (type === 'arrow') {
1117
- const arrow = xnew$1(`<div style="width: 100%; height: 0.5em; border-right: 0.12em solid currentColor; border-bottom: 0.12em solid currentColor; box-sizing: border-box; transform-origin: center center;">`);
1118
- return {
1119
- transition(status) {
1120
- arrow.element.style.transform = `rotate(${status * 90 - 45}deg)`;
1121
- }
1122
- };
1132
+ const arrow = xnew$1(`<div style="width: 100%; height: 0.55em; border-right: 0.12em solid currentColor; border-bottom: 0.12em solid currentColor; box-sizing: border-box; transform-origin: center;">`);
1133
+ arrow.element.style.transform = `rotate(${internal.rate * 90 - 45}deg)`;
1134
+ internal.on('-transition', ({ rate }) => {
1135
+ arrow.element.style.transform = `rotate(${rate * 90 - 45}deg)`;
1136
+ });
1123
1137
  }
1124
1138
  else if (type === 'plusminus') {
1125
- xnew$1(`<div style="position: absolute; width: 100%; border-top: 0.06em solid currentColor; border-bottom: 0.06em solid currentColor; box-sizing: border-box; transform-origin: center center;">`);
1126
- const line2 = xnew$1(`<div style="position: absolute; width: 100%; border-top: 0.06em solid currentColor; border-bottom: 0.06em solid currentColor; box-sizing: border-box; transform-origin: center center;">`);
1139
+ const line1 = xnew$1(`<div style="position: absolute; width: 100%; border-top: 0.06em solid currentColor; border-bottom: 0.06em solid currentColor; box-sizing: border-box; transform-origin: center;">`);
1140
+ const line2 = xnew$1(`<div style="position: absolute; width: 100%; border-top: 0.06em solid currentColor; border-bottom: 0.06em solid currentColor; box-sizing: border-box; transform-origin: center;">`);
1127
1141
  line2.element.style.transform = `rotate(90deg)`;
1128
- return {
1129
- transition(status) {
1130
- line2.element.style.opacity = `${1.0 - status}`;
1131
- }
1132
- };
1142
+ line2.element.style.opacity = `${1.0 - internal.rate}`;
1143
+ internal.on('-transition', ({ rate }) => {
1144
+ line1.element.style.transform = `rotate(${90 + rate * 90}deg)`;
1145
+ line2.element.style.transform = `rotate(${rate * 180}deg)`;
1146
+ });
1133
1147
  }
1134
1148
  }
1135
- function AccordionContent(content, { open = false, duration = 200, easing = 'ease' } = {}) {
1136
- const frame = xnew$1.context('xnew.accordionframe');
1137
- const outer = xnew$1.nest('<div>');
1138
- const inner = xnew$1.nest('<div style="padding: 0; display: flex; flex-direction: column; box-sizing: border-box;">');
1139
- let status = open ? 1.0 : 0.0;
1140
- outer.style.display = status ? 'block' : 'none';
1141
- frame.emit('-transition', { status });
1142
- frame.on('-open', () => {
1143
- xnew$1.transition((x) => {
1144
- status = x;
1145
- frame.emit('-transition', { status });
1146
- content.transition(status);
1147
- }, duration, easing);
1148
- });
1149
- frame.on('-close', () => {
1150
- xnew$1.transition((x) => {
1151
- status = 1.0 - x;
1152
- frame.emit('-transition', { status });
1153
- content.transition(status);
1154
- }, duration, easing);
1149
+ function AccordionContent(content, {} = {}) {
1150
+ const internal = xnew$1.context('xnew.accordionframe');
1151
+ xnew$1.nest(`<div style="display: ${internal.open ? 'block' : 'none'};">`);
1152
+ xnew$1.nest('<div style="padding: 0; display: flex; flex-direction: column; box-sizing: border-box;">');
1153
+ internal.on('-transition', ({ rate }) => {
1154
+ content.transition({ element: content.element, rate });
1155
1155
  });
1156
1156
  return {
1157
- get status() {
1158
- return status;
1159
- },
1160
- transition(status) {
1161
- outer.style.display = 'block';
1162
- if (status === 0.0) {
1163
- outer.style.display = 'none';
1157
+ transition({ element, rate }) {
1158
+ const wrapper = element.parentElement;
1159
+ wrapper.style.display = 'block';
1160
+ if (rate === 0.0) {
1161
+ wrapper.style.display = 'none';
1164
1162
  }
1165
- else if (status < 1.0) {
1166
- Object.assign(outer.style, { height: inner.offsetHeight * status + 'px', overflow: 'hidden', opacity: status });
1163
+ else if (rate < 1.0) {
1164
+ Object.assign(wrapper.style, { height: element.offsetHeight * rate + 'px', overflow: 'hidden', opacity: rate });
1167
1165
  }
1168
1166
  else {
1169
- Object.assign(outer.style, { height: 'auto', overflow: 'visible', opacity: 1.0 });
1167
+ Object.assign(wrapper.style, { height: 'auto', overflow: 'visible', opacity: 1.0 });
1170
1168
  }
1171
- },
1169
+ }
1172
1170
  };
1173
1171
  }
1174
1172
 
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "keywords": [
5
5
  "Component-Oriented Programming"
6
6
  ],
7
- "version": "0.1.4",
7
+ "version": "0.1.6",
8
8
  "main": "dist/xnew.js",
9
9
  "module": "dist/xnew.mjs",
10
10
  "types": "dist/xnew.d.ts",