@destyler/hover-card 0.0.7-beta.7 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,100 +1,104 @@
1
- import * as _zag_js_anatomy from '@zag-js/anatomy';
2
- import { DirectionProperty, CommonProperties, PropTypes, RequiredBy, NormalizeProps } from '@zag-js/types';
3
- import * as _zag_js_core from '@zag-js/core';
4
- import { StateMachine, Machine } from '@zag-js/core';
5
- import { PositioningOptions, Placement } from '@zag-js/popper';
6
- export { Placement, PositioningOptions } from '@zag-js/popper';
7
-
8
- declare const anatomy: _zag_js_anatomy.AnatomyInstance<"arrow" | "arrowTip" | "trigger" | "positioner" | "content">;
1
+ import * as _destyler_anatomy0 from "@destyler/anatomy";
2
+ import { Placement, PositioningOptions } from "@destyler/popper";
3
+ import * as _destyler_xstate0 from "@destyler/xstate";
4
+ import { AnyEventObject, Machine, XSend, XState } from "@destyler/xstate";
5
+ import { CommonProperties, DirectionProperty, NormalizeProps, PropTypes, RequiredBy } from "@destyler/types";
9
6
 
7
+ //#region src/anatomy.d.ts
8
+ declare const anatomy: _destyler_anatomy0.AnatomyInstance<"arrow" | "arrowTip" | "trigger" | "positioner" | "content">;
9
+ //#endregion
10
+ //#region src/types.d.ts
10
11
  interface OpenChangeDetails {
11
- open: boolean;
12
+ open: boolean;
12
13
  }
13
14
  type ElementIds = Partial<{
14
- trigger: string;
15
- content: string;
16
- positioner: string;
17
- arrow: string;
15
+ trigger: string;
16
+ content: string;
17
+ positioner: string;
18
+ arrow: string;
18
19
  }>;
19
20
  interface PublicContext extends DirectionProperty, CommonProperties {
20
- /**
21
- * The ids of the elements in the popover. Useful for composition.
22
- */
23
- 'ids'?: ElementIds | undefined;
24
- /**
25
- * Function called when the hover card opens or closes.
26
- */
27
- 'onOpenChange'?: ((details: OpenChangeDetails) => void) | undefined;
28
- /**
29
- * The duration from when the mouse enters the trigger until the hover card opens.
30
- * @default 700
31
- */
32
- 'openDelay': number;
33
- /**
34
- * The duration from when the mouse leaves the trigger or content until the hover card closes.
35
- * @default 300
36
- */
37
- 'closeDelay': number;
38
- /**
39
- * Whether the hover card is open
40
- */
41
- 'open'?: boolean | undefined;
42
- /**
43
- * Whether the hover card is controlled by the user
44
- */
45
- 'open.controlled'?: boolean | undefined;
46
- /**
47
- * The user provided options used to position the popover content
48
- */
49
- 'positioning': PositioningOptions;
21
+ /**
22
+ * The ids of the elements in the popover. Useful for composition.
23
+ */
24
+ 'ids'?: ElementIds | undefined;
25
+ /**
26
+ * Function called when the hover card opens or closes.
27
+ */
28
+ 'onOpenChange'?: ((details: OpenChangeDetails) => void) | undefined;
29
+ /**
30
+ * The duration from when the mouse enters the trigger until the hover card opens.
31
+ * @default 700
32
+ */
33
+ 'openDelay': number;
34
+ /**
35
+ * The duration from when the mouse leaves the trigger or content until the hover card closes.
36
+ * @default 300
37
+ */
38
+ 'closeDelay': number;
39
+ /**
40
+ * Whether the hover card is open
41
+ */
42
+ 'open'?: boolean | undefined;
43
+ /**
44
+ * Whether the hover card is controlled by the user
45
+ */
46
+ 'open.controlled'?: boolean | undefined;
47
+ /**
48
+ * The user provided options used to position the popover content
49
+ */
50
+ 'positioning': PositioningOptions;
50
51
  }
51
52
  interface PrivateContext {
52
- /**
53
- * @internal
54
- * The computed placement of the tooltip.
55
- */
56
- currentPlacement?: Placement | undefined;
57
- /**
58
- * @internal
59
- * Whether the hover card is open by pointer
60
- */
61
- isPointer?: boolean | undefined;
53
+ /**
54
+ * @internal
55
+ * The computed placement of the tooltip.
56
+ */
57
+ currentPlacement?: Placement | undefined;
58
+ /**
59
+ * @internal
60
+ * Whether the hover card is open by pointer
61
+ */
62
+ isPointer?: boolean | undefined;
62
63
  }
63
64
  type ComputedContext = Readonly<{}>;
64
65
  type UserDefinedContext = RequiredBy<PublicContext, 'id'>;
65
66
  type MachineContext = PublicContext & PrivateContext & ComputedContext;
66
67
  interface MachineState {
67
- value: 'opening' | 'open' | 'closing' | 'closed';
68
- tags: 'open' | 'closed';
68
+ value: 'opening' | 'open' | 'closing' | 'closed';
69
+ tags: 'open' | 'closed';
69
70
  }
70
- type State = StateMachine.State<MachineContext, MachineState>;
71
- type Send = StateMachine.Send<StateMachine.AnyEventObject>;
72
- type Service = Machine<MachineContext, MachineState, StateMachine.AnyEventObject>;
71
+ type State = XState<MachineContext, MachineState>;
72
+ type Send = XSend<AnyEventObject>;
73
+ type Service = Machine<MachineContext, MachineState, AnyEventObject>;
73
74
  interface MachineApi<T extends PropTypes = PropTypes> {
74
- /**
75
- * Whether the hover card is open
76
- */
77
- open: boolean;
78
- /**
79
- * Function to open the hover card
80
- */
81
- setOpen: (open: boolean) => void;
82
- /**
83
- * Function to reposition the popover
84
- */
85
- reposition: (options?: Partial<PositioningOptions>) => void;
86
- getArrowProps: () => T['element'];
87
- getArrowTipProps: () => T['element'];
88
- getTriggerProps: () => T['element'];
89
- getPositionerProps: () => T['element'];
90
- getContentProps: () => T['element'];
75
+ /**
76
+ * Whether the hover card is open
77
+ */
78
+ open: boolean;
79
+ /**
80
+ * Function to open the hover card
81
+ */
82
+ setOpen: (open: boolean) => void;
83
+ /**
84
+ * Function to reposition the popover
85
+ */
86
+ reposition: (options?: Partial<PositioningOptions>) => void;
87
+ getArrowProps: () => T['element'];
88
+ getArrowTipProps: () => T['element'];
89
+ getTriggerProps: () => T['element'];
90
+ getPositionerProps: () => T['element'];
91
+ getContentProps: () => T['element'];
91
92
  }
92
-
93
+ //#endregion
94
+ //#region src/connect.d.ts
93
95
  declare function connect<T extends PropTypes>(state: State, send: Send, normalize: NormalizeProps<T>): MachineApi<T>;
94
-
95
- declare function machine(userContext: UserDefinedContext): _zag_js_core.Machine<MachineContext, MachineState, _zag_js_core.StateMachine.AnyEventObject>;
96
-
97
- declare const props: ("ids" | "onOpenChange" | "openDelay" | "closeDelay" | "open" | "open.controlled" | "positioning" | "id" | "dir" | "getRootNode")[];
98
- declare const splitProps: <Props extends Partial<UserDefinedContext>>(props: Props) => [Partial<UserDefinedContext>, Omit<Props, "ids" | "onOpenChange" | "openDelay" | "closeDelay" | "open" | "open.controlled" | "positioning" | "id" | "dir" | "getRootNode">];
99
-
100
- export { type MachineApi as Api, type UserDefinedContext as Context, type ElementIds, type OpenChangeDetails, type Service, anatomy, connect, machine, props, splitProps };
96
+ //#endregion
97
+ //#region src/machine.d.ts
98
+ declare function machine(userContext: UserDefinedContext): _destyler_xstate0.Machine<MachineContext, MachineState, _destyler_xstate0.AnyEventObject>;
99
+ //#endregion
100
+ //#region src/props.d.ts
101
+ declare const props: ("open" | "id" | "ids" | "onOpenChange" | "openDelay" | "closeDelay" | "open.controlled" | "positioning" | "dir" | "getRootNode")[];
102
+ declare const splitProps: <Props extends Partial<UserDefinedContext>>(props: Props) => [Partial<UserDefinedContext>, Omit<Props, "open" | "id" | "ids" | "onOpenChange" | "openDelay" | "closeDelay" | "open.controlled" | "positioning" | "dir" | "getRootNode">];
103
+ //#endregion
104
+ export { type MachineApi as Api, type UserDefinedContext as Context, type ElementIds, type OpenChangeDetails, type Placement, type PositioningOptions, type Service, anatomy, connect, machine, props, splitProps };
package/dist/index.js ADDED
@@ -0,0 +1,330 @@
1
+ import { createAnatomy } from "@destyler/anatomy";
2
+ import { getPlacement, getPlacementStyles } from "@destyler/popper";
3
+ import { createScope } from "@destyler/dom";
4
+ import { trackDismissableElement } from "@destyler/dismissable";
5
+ import { compact, createSplitProps } from "@destyler/utils";
6
+ import { createMachine, guards } from "@destyler/xstate";
7
+ import { createProps } from "@destyler/types";
8
+
9
+ //#region src/anatomy.ts
10
+ const anatomy = createAnatomy("hoverCard").parts("arrow", "arrowTip", "trigger", "positioner", "content");
11
+ const parts = anatomy.build();
12
+
13
+ //#endregion
14
+ //#region src/dom.ts
15
+ const dom = createScope({
16
+ getTriggerId: (ctx) => ctx.ids?.trigger ?? `hover-card:${ctx.id}:trigger`,
17
+ getContentId: (ctx) => ctx.ids?.content ?? `hover-card:${ctx.id}:content`,
18
+ getPositionerId: (ctx) => ctx.ids?.positioner ?? `hover-card:${ctx.id}:popper`,
19
+ getArrowId: (ctx) => ctx.ids?.arrow ?? `hover-card:${ctx.id}:arrow`,
20
+ getTriggerEl: (ctx) => dom.getById(ctx, dom.getTriggerId(ctx)),
21
+ getContentEl: (ctx) => dom.getById(ctx, dom.getContentId(ctx)),
22
+ getPositionerEl: (ctx) => dom.getById(ctx, dom.getPositionerId(ctx))
23
+ });
24
+
25
+ //#endregion
26
+ //#region src/connect.ts
27
+ function connect(state, send, normalize) {
28
+ const open = state.hasTag("open");
29
+ const popperStyles = getPlacementStyles({
30
+ ...state.context.positioning,
31
+ placement: state.context.currentPlacement
32
+ });
33
+ return {
34
+ open,
35
+ setOpen(nextOpen) {
36
+ if (nextOpen === open) return;
37
+ send(nextOpen ? "OPEN" : "CLOSE");
38
+ },
39
+ reposition(options = {}) {
40
+ send({
41
+ type: "POSITIONING.SET",
42
+ options
43
+ });
44
+ },
45
+ getArrowProps() {
46
+ return normalize.element({
47
+ id: dom.getArrowId(state.context),
48
+ ...parts.arrow.attrs,
49
+ dir: state.context.dir,
50
+ style: popperStyles.arrow
51
+ });
52
+ },
53
+ getArrowTipProps() {
54
+ return normalize.element({
55
+ ...parts.arrowTip.attrs,
56
+ dir: state.context.dir,
57
+ style: popperStyles.arrowTip
58
+ });
59
+ },
60
+ getTriggerProps() {
61
+ return normalize.element({
62
+ ...parts.trigger.attrs,
63
+ "dir": state.context.dir,
64
+ "data-placement": state.context.currentPlacement,
65
+ "id": dom.getTriggerId(state.context),
66
+ "data-state": open ? "open" : "closed",
67
+ onPointerEnter(event) {
68
+ if (event.pointerType === "touch") return;
69
+ send({
70
+ type: "POINTER_ENTER",
71
+ src: "trigger"
72
+ });
73
+ },
74
+ onPointerLeave(event) {
75
+ if (event.pointerType === "touch") return;
76
+ send({
77
+ type: "POINTER_LEAVE",
78
+ src: "trigger"
79
+ });
80
+ },
81
+ onFocus() {
82
+ send("TRIGGER_FOCUS");
83
+ },
84
+ onBlur() {
85
+ send("TRIGGER_BLUR");
86
+ }
87
+ });
88
+ },
89
+ getPositionerProps() {
90
+ return normalize.element({
91
+ id: dom.getPositionerId(state.context),
92
+ ...parts.positioner.attrs,
93
+ dir: state.context.dir,
94
+ style: popperStyles.floating
95
+ });
96
+ },
97
+ getContentProps() {
98
+ return normalize.element({
99
+ ...parts.content.attrs,
100
+ "dir": state.context.dir,
101
+ "id": dom.getContentId(state.context),
102
+ "hidden": !open,
103
+ "data-state": open ? "open" : "closed",
104
+ "data-placement": state.context.currentPlacement,
105
+ onPointerEnter(event) {
106
+ if (event.pointerType === "touch") return;
107
+ send({
108
+ type: "POINTER_ENTER",
109
+ src: "content"
110
+ });
111
+ },
112
+ onPointerLeave(event) {
113
+ if (event.pointerType === "touch") return;
114
+ send({
115
+ type: "POINTER_LEAVE",
116
+ src: "content"
117
+ });
118
+ }
119
+ });
120
+ }
121
+ };
122
+ }
123
+
124
+ //#endregion
125
+ //#region src/machine.ts
126
+ const { not, and } = guards;
127
+ function machine(userContext) {
128
+ const ctx = compact(userContext);
129
+ return createMachine({
130
+ id: "hover-card",
131
+ initial: ctx.open ? "open" : "closed",
132
+ context: {
133
+ openDelay: 700,
134
+ closeDelay: 300,
135
+ currentPlacement: void 0,
136
+ ...ctx,
137
+ positioning: {
138
+ placement: "bottom",
139
+ ...ctx.positioning
140
+ }
141
+ },
142
+ watch: { open: ["toggleVisibility"] },
143
+ states: {
144
+ closed: {
145
+ tags: ["closed"],
146
+ entry: ["clearIsPointer"],
147
+ on: {
148
+ "CONTROLLED.OPEN": "open",
149
+ "POINTER_ENTER": {
150
+ target: "opening",
151
+ actions: ["setIsPointer"]
152
+ },
153
+ "TRIGGER_FOCUS": "opening",
154
+ "OPEN": "opening"
155
+ }
156
+ },
157
+ opening: {
158
+ tags: ["closed"],
159
+ after: { OPEN_DELAY: [{
160
+ guard: "isOpenControlled",
161
+ actions: ["invokeOnOpen"]
162
+ }, {
163
+ target: "open",
164
+ actions: ["invokeOnOpen"]
165
+ }] },
166
+ on: {
167
+ "CONTROLLED.OPEN": "open",
168
+ "CONTROLLED.CLOSE": "closed",
169
+ "POINTER_LEAVE": [{
170
+ guard: "isOpenControlled",
171
+ actions: ["invokeOnClose", "toggleVisibility"]
172
+ }, {
173
+ target: "closed",
174
+ actions: ["invokeOnClose"]
175
+ }],
176
+ "TRIGGER_BLUR": [{
177
+ guard: and("isOpenControlled", not("isPointer")),
178
+ actions: ["invokeOnClose", "toggleVisibility"]
179
+ }, {
180
+ guard: not("isPointer"),
181
+ target: "closed",
182
+ actions: ["invokeOnClose"]
183
+ }],
184
+ "CLOSE": [{
185
+ guard: "isOpenControlled",
186
+ actions: ["invokeOnClose", "toggleVisibility"]
187
+ }, {
188
+ target: "closed",
189
+ actions: ["invokeOnClose"]
190
+ }]
191
+ }
192
+ },
193
+ open: {
194
+ tags: ["open"],
195
+ activities: ["trackDismissableElement", "trackPositioning"],
196
+ on: {
197
+ "CONTROLLED.CLOSE": "closed",
198
+ "POINTER_ENTER": { actions: ["setIsPointer"] },
199
+ "POINTER_LEAVE": "closing",
200
+ "CLOSE": [{
201
+ guard: "isOpenControlled",
202
+ actions: ["invokeOnClose"]
203
+ }, {
204
+ target: "closed",
205
+ actions: ["invokeOnClose"]
206
+ }],
207
+ "TRIGGER_BLUR": [{
208
+ guard: and("isOpenControlled", not("isPointer")),
209
+ actions: ["invokeOnClose"]
210
+ }, {
211
+ guard: not("isPointer"),
212
+ target: "closed",
213
+ actions: ["invokeOnClose"]
214
+ }],
215
+ "POSITIONING.SET": { actions: "reposition" }
216
+ }
217
+ },
218
+ closing: {
219
+ tags: ["open"],
220
+ activities: ["trackPositioning"],
221
+ after: { CLOSE_DELAY: [{
222
+ guard: "isOpenControlled",
223
+ actions: ["invokeOnClose"]
224
+ }, {
225
+ target: "closed",
226
+ actions: ["invokeOnClose"]
227
+ }] },
228
+ on: {
229
+ "CONTROLLED.CLOSE": "closed",
230
+ "CONTROLLED.OPEN": "open",
231
+ "POINTER_ENTER": {
232
+ target: "open",
233
+ actions: ["setIsPointer"]
234
+ }
235
+ }
236
+ }
237
+ }
238
+ }, {
239
+ delays: {
240
+ OPEN_DELAY: (ctx$1) => ctx$1.openDelay,
241
+ CLOSE_DELAY: (ctx$1) => ctx$1.closeDelay
242
+ },
243
+ guards: {
244
+ isPointer: (ctx$1) => !!ctx$1.isPointer,
245
+ isOpenControlled: (ctx$1) => !!ctx$1["open.controlled"]
246
+ },
247
+ activities: {
248
+ trackPositioning(ctx$1) {
249
+ ctx$1.currentPlacement ||= ctx$1.positioning.placement;
250
+ const getPositionerEl = () => dom.getPositionerEl(ctx$1);
251
+ return getPlacement(dom.getTriggerEl(ctx$1), getPositionerEl, {
252
+ ...ctx$1.positioning,
253
+ defer: true,
254
+ onComplete(data) {
255
+ ctx$1.currentPlacement = data.placement;
256
+ }
257
+ });
258
+ },
259
+ trackDismissableElement(ctx$1, _evt, { send }) {
260
+ const getContentEl = () => dom.getContentEl(ctx$1);
261
+ return trackDismissableElement(getContentEl, {
262
+ defer: true,
263
+ exclude: [dom.getTriggerEl(ctx$1)],
264
+ onDismiss() {
265
+ send({
266
+ type: "CLOSE",
267
+ src: "interact-outside"
268
+ });
269
+ },
270
+ onFocusOutside(event) {
271
+ event.preventDefault();
272
+ }
273
+ });
274
+ }
275
+ },
276
+ actions: {
277
+ invokeOnClose(ctx$1) {
278
+ ctx$1.onOpenChange?.({ open: false });
279
+ },
280
+ invokeOnOpen(ctx$1) {
281
+ ctx$1.onOpenChange?.({ open: true });
282
+ },
283
+ setIsPointer(ctx$1) {
284
+ ctx$1.isPointer = true;
285
+ },
286
+ clearIsPointer(ctx$1) {
287
+ ctx$1.isPointer = false;
288
+ },
289
+ reposition(ctx$1, evt) {
290
+ const getPositionerEl = () => dom.getPositionerEl(ctx$1);
291
+ getPlacement(dom.getTriggerEl(ctx$1), getPositionerEl, {
292
+ ...ctx$1.positioning,
293
+ ...evt.options,
294
+ defer: true,
295
+ listeners: false,
296
+ onComplete(data) {
297
+ ctx$1.currentPlacement = data.placement;
298
+ }
299
+ });
300
+ },
301
+ toggleVisibility(ctx$1, evt, { send }) {
302
+ queueMicrotask(() => {
303
+ send({
304
+ type: ctx$1.open ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE",
305
+ previousEvent: evt
306
+ });
307
+ });
308
+ }
309
+ }
310
+ });
311
+ }
312
+
313
+ //#endregion
314
+ //#region src/props.ts
315
+ const props = createProps()([
316
+ "closeDelay",
317
+ "dir",
318
+ "getRootNode",
319
+ "id",
320
+ "ids",
321
+ "onOpenChange",
322
+ "open.controlled",
323
+ "open",
324
+ "openDelay",
325
+ "positioning"
326
+ ]);
327
+ const splitProps = createSplitProps(props);
328
+
329
+ //#endregion
330
+ export { anatomy, connect, machine, props, splitProps };
package/package.json CHANGED
@@ -1,37 +1,33 @@
1
1
  {
2
2
  "name": "@destyler/hover-card",
3
3
  "type": "module",
4
- "version": "0.0.7-beta.7",
4
+ "version": "0.1.0",
5
5
  "description": "for sighted users to preview content available behind a link.",
6
6
  "author": "Elone Hoo <elonehoo@gmail.com>",
7
7
  "license": "MIT",
8
8
  "exports": {
9
- ".": {
10
- "types": "./dist/index.d.mts",
11
- "default": "./dist/index.mjs"
12
- },
13
- "./*": "./*"
9
+ ".": "./dist/index.js"
14
10
  },
15
- "main": "dist/index.cjs",
16
- "module": "dist/index.mjs",
11
+ "main": "dist/index.js",
12
+ "module": "dist/index.js",
17
13
  "types": "dist/index.d.ts",
18
14
  "files": [
19
15
  "*.d.ts",
20
16
  "dist"
21
17
  ],
22
18
  "dependencies": {
23
- "@zag-js/anatomy": "^0.82.1",
24
- "@zag-js/core": "^0.82.1",
25
- "@zag-js/dismissable": "^0.82.1",
26
- "@zag-js/dom-query": "^0.82.1",
27
- "@zag-js/popper": "^0.82.1",
28
- "@zag-js/types": "^0.82.1",
29
- "@zag-js/utils": "^0.82.1"
19
+ "@destyler/anatomy": "0.1.0",
20
+ "@destyler/dismissable": "0.1.0",
21
+ "@destyler/popper": "0.1.0",
22
+ "@destyler/dom": "0.1.0",
23
+ "@destyler/types": "0.1.0",
24
+ "@destyler/utils": "0.1.0",
25
+ "@destyler/xstate": "0.1.0"
30
26
  },
31
27
  "scripts": {
32
28
  "clear": "rimraf ./dist",
33
29
  "clear:node_modules": "rimraf ./node_modules",
34
- "build": "pnpm run clear && unbuild",
35
- "stub": "unbuild --stub"
30
+ "build": "pnpm run clear && tsdown",
31
+ "watch": "tsdown --watch"
36
32
  }
37
33
  }