@destyler/popover 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.js ADDED
@@ -0,0 +1,407 @@
1
+ import { createAnatomy } from "@destyler/anatomy";
2
+ import { createScope, dataAttr, getFocusables, getInitialFocus, isSafari, proxyTabFocus, raf } from "@destyler/dom";
3
+ import { getPlacement, getPlacementStyles } from "@destyler/popper";
4
+ import { ariaHidden } from "@destyler/aria-hidden";
5
+ import { trackDismissableElement } from "@destyler/dismissable";
6
+ import { trapFocus } from "@destyler/focus-trap";
7
+ import { preventBodyScroll } from "@destyler/remove-scroll";
8
+ import { compact, createSplitProps } from "@destyler/utils";
9
+ import { createMachine } from "@destyler/xstate";
10
+ import { createProps } from "@destyler/types";
11
+
12
+ //#region src/anatomy.ts
13
+ const anatomy = createAnatomy("popover").parts("arrow", "arrowTip", "anchor", "trigger", "indicator", "positioner", "content", "title", "description", "closeTrigger");
14
+ const parts = anatomy.build();
15
+
16
+ //#endregion
17
+ //#region src/dom.ts
18
+ const dom = createScope({
19
+ getAnchorId: (ctx) => ctx.ids?.anchor ?? `popover:${ctx.id}:anchor`,
20
+ getTriggerId: (ctx) => ctx.ids?.trigger ?? `popover:${ctx.id}:trigger`,
21
+ getContentId: (ctx) => ctx.ids?.content ?? `popover:${ctx.id}:content`,
22
+ getPositionerId: (ctx) => ctx.ids?.positioner ?? `popover:${ctx.id}:popper`,
23
+ getArrowId: (ctx) => ctx.ids?.arrow ?? `popover:${ctx.id}:arrow`,
24
+ getTitleId: (ctx) => ctx.ids?.title ?? `popover:${ctx.id}:title`,
25
+ getDescriptionId: (ctx) => ctx.ids?.description ?? `popover:${ctx.id}:desc`,
26
+ getCloseTriggerId: (ctx) => ctx.ids?.closeTrigger ?? `popover:${ctx.id}:close`,
27
+ getAnchorEl: (ctx) => dom.getById(ctx, dom.getAnchorId(ctx)),
28
+ getTriggerEl: (ctx) => dom.getById(ctx, dom.getTriggerId(ctx)),
29
+ getContentEl: (ctx) => dom.getById(ctx, dom.getContentId(ctx)),
30
+ getPositionerEl: (ctx) => dom.getById(ctx, dom.getPositionerId(ctx)),
31
+ getTitleEl: (ctx) => dom.getById(ctx, dom.getTitleId(ctx)),
32
+ getDescriptionEl: (ctx) => dom.getById(ctx, dom.getDescriptionId(ctx)),
33
+ getFocusableEls: (ctx) => getFocusables(dom.getContentEl(ctx)),
34
+ getFirstFocusableEl: (ctx) => dom.getFocusableEls(ctx)[0]
35
+ });
36
+
37
+ //#endregion
38
+ //#region src/connect.ts
39
+ function connect(state, send, normalize) {
40
+ const open = state.matches("open");
41
+ const currentPlacement = state.context.currentPlacement;
42
+ const portalled = state.context.currentPortalled;
43
+ const rendered = state.context.renderedElements;
44
+ const popperStyles = getPlacementStyles({
45
+ ...state.context.positioning,
46
+ placement: currentPlacement
47
+ });
48
+ return {
49
+ portalled,
50
+ open,
51
+ setOpen(nextOpen) {
52
+ if (nextOpen === open) return;
53
+ send(nextOpen ? "OPEN" : "CLOSE");
54
+ },
55
+ reposition(options = {}) {
56
+ send({
57
+ type: "POSITIONING.SET",
58
+ options
59
+ });
60
+ },
61
+ getArrowProps() {
62
+ return normalize.element({
63
+ id: dom.getArrowId(state.context),
64
+ ...parts.arrow.attrs,
65
+ dir: state.context.dir,
66
+ style: popperStyles.arrow
67
+ });
68
+ },
69
+ getArrowTipProps() {
70
+ return normalize.element({
71
+ ...parts.arrowTip.attrs,
72
+ dir: state.context.dir,
73
+ style: popperStyles.arrowTip
74
+ });
75
+ },
76
+ getAnchorProps() {
77
+ return normalize.element({
78
+ ...parts.anchor.attrs,
79
+ dir: state.context.dir,
80
+ id: dom.getAnchorId(state.context)
81
+ });
82
+ },
83
+ getTriggerProps() {
84
+ return normalize.button({
85
+ ...parts.trigger.attrs,
86
+ "dir": state.context.dir,
87
+ "type": "button",
88
+ "data-placement": currentPlacement,
89
+ "id": dom.getTriggerId(state.context),
90
+ "aria-haspopup": "dialog",
91
+ "aria-expanded": open,
92
+ "data-state": open ? "open" : "closed",
93
+ "aria-controls": dom.getContentId(state.context),
94
+ onPointerDown(event) {
95
+ if (isSafari()) event.currentTarget.focus();
96
+ },
97
+ onClick(event) {
98
+ if (event.defaultPrevented) return;
99
+ send("TOGGLE");
100
+ },
101
+ onBlur(event) {
102
+ send({
103
+ type: "TRIGGER_BLUR",
104
+ target: event.relatedTarget
105
+ });
106
+ }
107
+ });
108
+ },
109
+ getIndicatorProps() {
110
+ return normalize.element({
111
+ ...parts.indicator.attrs,
112
+ "dir": state.context.dir,
113
+ "data-state": open ? "open" : "closed"
114
+ });
115
+ },
116
+ getPositionerProps() {
117
+ return normalize.element({
118
+ id: dom.getPositionerId(state.context),
119
+ ...parts.positioner.attrs,
120
+ dir: state.context.dir,
121
+ style: popperStyles.floating
122
+ });
123
+ },
124
+ getContentProps() {
125
+ return normalize.element({
126
+ ...parts.content.attrs,
127
+ "dir": state.context.dir,
128
+ "id": dom.getContentId(state.context),
129
+ "tabIndex": -1,
130
+ "role": "dialog",
131
+ "hidden": !open,
132
+ "data-state": open ? "open" : "closed",
133
+ "data-expanded": dataAttr(open),
134
+ "aria-labelledby": rendered.title ? dom.getTitleId(state.context) : void 0,
135
+ "aria-describedby": rendered.description ? dom.getDescriptionId(state.context) : void 0,
136
+ "data-placement": currentPlacement
137
+ });
138
+ },
139
+ getTitleProps() {
140
+ return normalize.element({
141
+ ...parts.title.attrs,
142
+ id: dom.getTitleId(state.context),
143
+ dir: state.context.dir
144
+ });
145
+ },
146
+ getDescriptionProps() {
147
+ return normalize.element({
148
+ ...parts.description.attrs,
149
+ id: dom.getDescriptionId(state.context),
150
+ dir: state.context.dir
151
+ });
152
+ },
153
+ getCloseTriggerProps() {
154
+ return normalize.button({
155
+ ...parts.closeTrigger.attrs,
156
+ "dir": state.context.dir,
157
+ "id": dom.getCloseTriggerId(state.context),
158
+ "type": "button",
159
+ "aria-label": "close",
160
+ onClick(event) {
161
+ if (event.defaultPrevented) return;
162
+ send("CLOSE");
163
+ }
164
+ });
165
+ }
166
+ };
167
+ }
168
+
169
+ //#endregion
170
+ //#region src/machine.ts
171
+ function machine(userContext) {
172
+ const ctx = compact(userContext);
173
+ return createMachine({
174
+ id: "popover",
175
+ initial: ctx.open ? "open" : "closed",
176
+ context: {
177
+ closeOnInteractOutside: true,
178
+ closeOnEscape: true,
179
+ autoFocus: true,
180
+ modal: false,
181
+ portalled: true,
182
+ positioning: {
183
+ placement: "bottom",
184
+ ...ctx.positioning
185
+ },
186
+ currentPlacement: void 0,
187
+ ...ctx,
188
+ renderedElements: {
189
+ title: true,
190
+ description: true
191
+ }
192
+ },
193
+ computed: { currentPortalled: (ctx$1) => !!ctx$1.modal || !!ctx$1.portalled },
194
+ watch: { open: ["toggleVisibility"] },
195
+ entry: ["checkRenderedElements"],
196
+ states: {
197
+ closed: { on: {
198
+ "CONTROLLED.OPEN": {
199
+ target: "open",
200
+ actions: ["setInitialFocus"]
201
+ },
202
+ "TOGGLE": [{
203
+ guard: "isOpenControlled",
204
+ actions: ["invokeOnOpen"]
205
+ }, {
206
+ target: "open",
207
+ actions: ["invokeOnOpen", "setInitialFocus"]
208
+ }],
209
+ "OPEN": [{
210
+ guard: "isOpenControlled",
211
+ actions: ["invokeOnOpen"]
212
+ }, {
213
+ target: "open",
214
+ actions: ["invokeOnOpen", "setInitialFocus"]
215
+ }]
216
+ } },
217
+ open: {
218
+ activities: [
219
+ "trapFocus",
220
+ "preventScroll",
221
+ "hideContentBelow",
222
+ "trackPositioning",
223
+ "trackDismissableElement",
224
+ "proxyTabFocus"
225
+ ],
226
+ on: {
227
+ "CONTROLLED.CLOSE": {
228
+ target: "closed",
229
+ actions: ["setFinalFocus"]
230
+ },
231
+ "CLOSE": [{
232
+ guard: "isOpenControlled",
233
+ actions: ["invokeOnClose"]
234
+ }, {
235
+ target: "closed",
236
+ actions: ["invokeOnClose", "setFinalFocus"]
237
+ }],
238
+ "TOGGLE": [{
239
+ guard: "isOpenControlled",
240
+ actions: ["invokeOnClose"]
241
+ }, {
242
+ target: "closed",
243
+ actions: ["invokeOnClose"]
244
+ }],
245
+ "POSITIONING.SET": { actions: "reposition" }
246
+ }
247
+ }
248
+ }
249
+ }, {
250
+ guards: { isOpenControlled: (ctx$1) => !!ctx$1["open.controlled"] },
251
+ activities: {
252
+ trackPositioning(ctx$1) {
253
+ ctx$1.currentPlacement = ctx$1.positioning.placement;
254
+ const anchorEl = dom.getAnchorEl(ctx$1) ?? dom.getTriggerEl(ctx$1);
255
+ const getPositionerEl = () => dom.getPositionerEl(ctx$1);
256
+ return getPlacement(anchorEl, getPositionerEl, {
257
+ ...ctx$1.positioning,
258
+ defer: true,
259
+ onComplete(data) {
260
+ ctx$1.currentPlacement = data.placement;
261
+ }
262
+ });
263
+ },
264
+ trackDismissableElement(ctx$1, _evt, { send }) {
265
+ const getContentEl = () => dom.getContentEl(ctx$1);
266
+ let restoreFocus = true;
267
+ return trackDismissableElement(getContentEl, {
268
+ pointerBlocking: ctx$1.modal,
269
+ exclude: dom.getTriggerEl(ctx$1),
270
+ defer: true,
271
+ onEscapeKeyDown(event) {
272
+ ctx$1.onEscapeKeyDown?.(event);
273
+ if (ctx$1.closeOnEscape) return;
274
+ event.preventDefault();
275
+ },
276
+ onInteractOutside(event) {
277
+ ctx$1.onInteractOutside?.(event);
278
+ if (event.defaultPrevented) return;
279
+ restoreFocus = !(event.detail.focusable || event.detail.contextmenu);
280
+ if (!ctx$1.closeOnInteractOutside) event.preventDefault();
281
+ },
282
+ onPointerDownOutside: ctx$1.onPointerDownOutside,
283
+ onFocusOutside: ctx$1.onFocusOutside,
284
+ persistentElements: ctx$1.persistentElements,
285
+ onDismiss() {
286
+ send({
287
+ type: "CLOSE",
288
+ src: "interact-outside",
289
+ restoreFocus
290
+ });
291
+ }
292
+ });
293
+ },
294
+ proxyTabFocus(ctx$1) {
295
+ if (ctx$1.modal || !ctx$1.portalled) return;
296
+ const getContentEl = () => dom.getContentEl(ctx$1);
297
+ return proxyTabFocus(getContentEl, {
298
+ triggerElement: dom.getTriggerEl(ctx$1),
299
+ defer: true,
300
+ onFocus(el) {
301
+ el.focus({ preventScroll: true });
302
+ }
303
+ });
304
+ },
305
+ hideContentBelow(ctx$1) {
306
+ if (!ctx$1.modal) return;
307
+ const getElements = () => [dom.getContentEl(ctx$1), dom.getTriggerEl(ctx$1)];
308
+ return ariaHidden(getElements, { defer: true });
309
+ },
310
+ preventScroll(ctx$1) {
311
+ if (!ctx$1.modal) return;
312
+ return preventBodyScroll(dom.getDoc(ctx$1));
313
+ },
314
+ trapFocus(ctx$1) {
315
+ if (!ctx$1.modal) return;
316
+ const contentEl = () => dom.getContentEl(ctx$1);
317
+ return trapFocus(contentEl, { initialFocus: () => getInitialFocus({
318
+ root: dom.getContentEl(ctx$1),
319
+ getInitialEl: ctx$1.initialFocusEl,
320
+ enabled: ctx$1.autoFocus
321
+ }) });
322
+ }
323
+ },
324
+ actions: {
325
+ reposition(ctx$1, evt) {
326
+ const anchorEl = dom.getAnchorEl(ctx$1) ?? dom.getTriggerEl(ctx$1);
327
+ const getPositionerEl = () => dom.getPositionerEl(ctx$1);
328
+ getPlacement(anchorEl, getPositionerEl, {
329
+ ...ctx$1.positioning,
330
+ ...evt.options,
331
+ defer: true,
332
+ listeners: false,
333
+ onComplete(data) {
334
+ ctx$1.currentPlacement = data.placement;
335
+ }
336
+ });
337
+ },
338
+ checkRenderedElements(ctx$1) {
339
+ raf(() => {
340
+ Object.assign(ctx$1.renderedElements, {
341
+ title: !!dom.getTitleEl(ctx$1),
342
+ description: !!dom.getDescriptionEl(ctx$1)
343
+ });
344
+ });
345
+ },
346
+ setInitialFocus(ctx$1) {
347
+ if (ctx$1.modal) return;
348
+ raf(() => {
349
+ const element = getInitialFocus({
350
+ root: dom.getContentEl(ctx$1),
351
+ getInitialEl: ctx$1.initialFocusEl,
352
+ enabled: ctx$1.autoFocus
353
+ });
354
+ element?.focus({ preventScroll: true });
355
+ });
356
+ },
357
+ setFinalFocus(ctx$1, evt) {
358
+ const restoreFocus = evt.restoreFocus ?? evt.previousEvent?.restoreFocus;
359
+ if (restoreFocus != null && !restoreFocus) return;
360
+ raf(() => {
361
+ const element = dom.getTriggerEl(ctx$1);
362
+ element?.focus({ preventScroll: true });
363
+ });
364
+ },
365
+ invokeOnOpen(ctx$1) {
366
+ ctx$1.onOpenChange?.({ open: true });
367
+ },
368
+ invokeOnClose(ctx$1) {
369
+ ctx$1.onOpenChange?.({ open: false });
370
+ },
371
+ toggleVisibility(ctx$1, evt, { send }) {
372
+ send({
373
+ type: ctx$1.open ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE",
374
+ previousEvent: evt
375
+ });
376
+ }
377
+ }
378
+ });
379
+ }
380
+
381
+ //#endregion
382
+ //#region src/props.ts
383
+ const props = createProps()([
384
+ "autoFocus",
385
+ "closeOnEscape",
386
+ "closeOnInteractOutside",
387
+ "dir",
388
+ "getRootNode",
389
+ "id",
390
+ "ids",
391
+ "initialFocusEl",
392
+ "modal",
393
+ "onEscapeKeyDown",
394
+ "onFocusOutside",
395
+ "onInteractOutside",
396
+ "onOpenChange",
397
+ "onPointerDownOutside",
398
+ "open.controlled",
399
+ "open",
400
+ "persistentElements",
401
+ "portalled",
402
+ "positioning"
403
+ ]);
404
+ const splitProps = createSplitProps(props);
405
+
406
+ //#endregion
407
+ export { anatomy, connect, machine, props, splitProps };
package/package.json CHANGED
@@ -1,40 +1,36 @@
1
1
  {
2
2
  "name": "@destyler/popover",
3
3
  "type": "module",
4
- "version": "0.0.7-beta.7",
4
+ "version": "0.1.0",
5
5
  "description": "displays rich content in a portal, triggered by a button.",
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/aria-hidden": "^0.82.1",
25
- "@zag-js/core": "^0.82.1",
26
- "@zag-js/dismissable": "^0.82.1",
27
- "@zag-js/dom-query": "^0.82.1",
28
- "@zag-js/focus-trap": "^0.82.1",
29
- "@zag-js/popper": "^0.82.1",
30
- "@zag-js/remove-scroll": "^0.82.1",
31
- "@zag-js/types": "^0.82.1",
32
- "@zag-js/utils": "^0.82.1"
19
+ "@destyler/anatomy": "0.1.0",
20
+ "@destyler/aria-hidden": "0.1.0",
21
+ "@destyler/dismissable": "0.1.0",
22
+ "@destyler/focus-trap": "0.1.0",
23
+ "@destyler/popper": "0.1.0",
24
+ "@destyler/remove-scroll": "0.1.0",
25
+ "@destyler/utils": "0.1.0",
26
+ "@destyler/dom": "0.1.0",
27
+ "@destyler/types": "0.1.0",
28
+ "@destyler/xstate": "0.1.0"
33
29
  },
34
30
  "scripts": {
35
31
  "clear": "rimraf ./dist",
36
32
  "clear:node_modules": "rimraf ./node_modules",
37
- "build": "pnpm run clear && unbuild",
38
- "stub": "unbuild --stub"
33
+ "build": "pnpm run clear && tsdown",
34
+ "watch": "tsdown --watch"
39
35
  }
40
36
  }