@bluepic/embed 0.4.0-next.161 → 0.4.0-next.163

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,19 +1,19 @@
1
1
  import type { BluepicField } from '@bluepic/types';
2
2
  /**
3
- * What clicking a hint chip does.
3
+ * What clicking a chip does.
4
4
  *
5
- * There is no per-field hint MODE any more — hints are simply on or off for the
6
- * whole campaign (`config.hints.enabled`). What a chip does is inferred from the
7
- * field itself:
5
+ * There is no per-field hint MODE — hints are simply on or off for the whole
6
+ * campaign (`config.hints`). What a chip does is inferred from the field itself:
8
7
  *
9
- * - `upload` — an image field that accepts a device upload. Clicking goes
10
- * straight to its own upload flow, which is the only thing anyone wants from
11
- * an image chip.
8
+ * - `upload` — the field accepts a device upload. Clicking goes straight to the
9
+ * file picker, which is the only thing anyone wants from a chip sitting on a
10
+ * picture. Other sources stay one tap away through the field itself.
12
11
  * - `focus` — everything else, including image fields restricted to libraries.
13
- * The chip scrolls the field into view and focuses its control, so the next
14
- * keystroke already types into it.
12
+ * The chip then does what the hitbox around it does: scroll the field into
13
+ * view and focus its control, so the next keystroke already types into it.
15
14
  */
16
15
  export type ChipAction = 'upload' | 'focus';
16
+ export declare function fieldHasChip(fieldType: BluepicField['type']): boolean;
17
17
  /**
18
18
  * `field.props` entries may be author expressions (functions) rather than
19
19
  * literals, so a prop can only be read through the host's evaluator — the same
@@ -4,10 +4,10 @@ import type { BluepicField } from '@bluepic/types';
4
4
  * Opens a field's own primary editing flow — for an image field, the "Select
5
5
  * image" popup (or the device file picker, when that's all it offers).
6
6
  *
7
- * Registered BY the field component, because only it knows that flow. An
8
- * `interact` hint reproducing it would mean duplicating image libraries,
9
- * cropping, background removal and auto-crop on the overlay, and then watching
10
- * the two copies drift.
7
+ * Registered BY the field component, because only it knows that flow. Having the
8
+ * overlay reproduce it would mean duplicating image libraries, cropping,
9
+ * background removal and auto-crop up there, and then watching the two copies
10
+ * drift.
11
11
  */
12
12
  export type FieldActivator = () => void;
13
13
  /**
@@ -18,13 +18,14 @@ export type FieldActivator = () => void;
18
18
  * provided by `BxTemplateEditor` and injected at both ends rather than threaded
19
19
  * through props.
20
20
  *
21
- * DESKTOP registers elements here and focuses them directly. MOBILE does not:
22
- * one field slide is on screen at a time, so "focus" there means swiping the
23
- * swiper to the right slide, which only `BxTemplateEditor` can do. That
24
- * asymmetry is why `focus()` is a controller method and not just a lookup.
21
+ * BOTH layouts register their elements here, because both end up focusing one:
22
+ * mobile mounts every swiper slide at once, so the control exists even while the
23
+ * swiper is still travelling to it. What differs is how it is brought on screen
24
+ * desktop scrolls the panel, mobile swipes and only `BxTemplateEditor` can
25
+ * do the latter, which is why `focus()` is a controller method and not just a
26
+ * lookup.
25
27
  */
26
28
  export type FieldFocusController = {
27
- /** Desktop only; mobile slides are addressed by index, not by element. */
28
29
  register(field: BluepicField, el: HTMLElement | null): void;
29
30
  focus(field: BluepicField): void;
30
31
  /** Field components self-register; pass `null` on unmount. */
@@ -42,16 +43,24 @@ export declare function useFieldFocus(): FieldFocusController | undefined;
42
43
  /** Marks the focused field for a moment so the eye can follow the jump. */
43
44
  export declare const FIELD_FOCUS_FLASH_CLASS = "bx-field-hint-target";
44
45
  /**
45
- * Scroll a field's control into view, flash it, and focus the first thing in it
46
- * that can take focus.
46
+ * Scroll a field's control into view, flash it, and focus what you type into
47
+ * falling back to whatever else in it can take focus.
47
48
  *
48
49
  * `block: 'nearest'` rather than 'center': the fields panel is a scroll
49
50
  * container, and centering yanks the whole list even when the target was
50
51
  * already comfortably visible.
52
+ *
53
+ * `scroll: false` for the MOBILE layout. Every slide is mounted at once inside
54
+ * swiper's transformed track, so a field that is off screen is off screen by
55
+ * TRANSFORM, not by scroll position — asking the browser to scroll it into view
56
+ * shifts the track's own scroller and leaves swiper's idea of the offset wrong.
57
+ * There, `slideTo` does the travelling and this only has to focus.
51
58
  */
52
- export declare function revealFieldElement(el: HTMLElement | null | undefined): HTMLElement | undefined;
59
+ export declare function revealFieldElement(el: HTMLElement | null | undefined, { scroll }?: {
60
+ scroll?: boolean;
61
+ }): HTMLElement | undefined;
53
62
  /**
54
- * Creates the desktop half: a registry keyed by the field object itself.
63
+ * The element/activator registry, keyed by the field object itself.
55
64
  *
56
65
  * A WeakMap (not a Map) because fields are plain objects off the serial — when
57
66
  * the serial is swapped the old field objects should simply be collectable,
@@ -9,13 +9,11 @@ export type { FieldHitbox } from './useFieldHitboxes';
9
9
  export { useHintReveal } from './useHintReveal';
10
10
  export { createFieldElementRegistry, provideFieldFocus, revealFieldElement, useFieldFocus, FIELD_FOCUS_KEY, FIELD_FOCUS_FLASH_CLASS, } from './fieldFocus';
11
11
  export type { FieldFocusController } from './fieldFocus';
12
- export { chipActionFor, readFieldProp } from './chipAction';
12
+ export { chipActionFor, fieldHasChip, readFieldProp } from './chipAction';
13
13
  export type { ChipAction } from './chipAction';
14
14
  export { textGeometryProbe } from './textProbe';
15
15
  export type { CaretGeometry, SelectionQuad, TextGeometryResult, TextIndexResult } from './textProbe';
16
16
  export { useCanvasTextEditing } from './useCanvasTextEditing';
17
17
  export type { CanvasTextState, SelectionHandle } from './useCanvasTextEditing';
18
- export { chooseChipPlacement, chipIsCentered, estimateChipWidth, arrowRotationForSide } from './placement';
19
- export type { ChipSide, PlacementResult } from './placement';
20
18
  export { useFieldActivator } from './fieldFocus';
21
19
  export type { FieldActivator } from './fieldFocus';
@@ -48,7 +48,7 @@ export declare function useFieldHitboxes(options: {
48
48
  data: Ref<{
49
49
  [k: string]: unknown;
50
50
  }>;
51
- /** Campaign gate (`config.hints?.enabled === true`). */
51
+ /** Campaign gate (`config.hints?.enabled !== false` — on by default). */
52
52
  enabled: Ref<boolean>;
53
53
  }): {
54
54
  hitboxes: Ref<{
@@ -1,7 +1,7 @@
1
1
  import { type Ref } from 'vue';
2
2
  export declare function useHintReveal(enabled: Ref<boolean>): {
3
3
  revealed: import("vue").ComputedRef<boolean>;
4
- hide: () => void;
4
+ reveal: () => void;
5
5
  onPointerEnter: (event: PointerEvent) => void;
6
6
  onPointerLeave: (event: PointerEvent) => void;
7
7
  onPointerDown: (event: PointerEvent) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bluepic/embed",
3
- "version": "0.4.0-next.161",
3
+ "version": "0.4.0-next.163",
4
4
  "description": "Bluepic embed sdk",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -1,72 +0,0 @@
1
- import type { BluepicField } from '@bluepic/types';
2
- /**
3
- * Where a hint chip sits relative to its hitbox.
4
- *
5
- * Deliberately a small synchronous solver rather than `@floating-ui`, which
6
- * this package already depends on: hints re-project on EVERY pan/zoom frame,
7
- * and floating-ui's `computePosition` is async and DOM-measuring. Running one
8
- * per hint per frame would lag the overlay behind the canvas it is annotating.
9
- * A pure function over numbers also means the placement rules can be tested
10
- * without a DOM.
11
- */
12
- export type ChipSide = 'top' | 'bottom' | 'left' | 'right';
13
- export type Rect = {
14
- x: number;
15
- y: number;
16
- width: number;
17
- height: number;
18
- };
19
- export type PlacementInput = {
20
- /** Hitbox AABB in overlay pixels. */
21
- box: Rect;
22
- /** Measured (or estimated) chip size. */
23
- chip: {
24
- width: number;
25
- height: number;
26
- };
27
- /** Visible overlay area. */
28
- viewport: {
29
- width: number;
30
- height: number;
31
- };
32
- /** Distance from the hitbox edge to the chip edge — room for the arrow. */
33
- gap: number;
34
- /** Keep-inside-the-viewport padding. */
35
- margin: number;
36
- };
37
- export type PlacementResult = {
38
- side: ChipSide;
39
- /** Chip top-left in overlay pixels. */
40
- x: number;
41
- y: number;
42
- /**
43
- * Arrow tip anchor, RELATIVE to the chip's top-left. Tracks the hitbox centre
44
- * even after the chip has been shifted to stay on screen — otherwise a
45
- * clamped chip would point at empty space.
46
- */
47
- arrowX: number;
48
- arrowY: number;
49
- };
50
- export declare function chipIsCentered(fieldType: BluepicField['type']): boolean;
51
- export declare function chooseChipPlacement(input: PlacementInput): PlacementResult;
52
- /**
53
- * Chip width before the real element has been measured. Only used for the very
54
- * first frame — the layer measures the rendered chip and re-solves — but a wild
55
- * guess here would place the first paint visibly wrong.
56
- */
57
- export declare function estimateChipWidth(label: string, max?: number): number;
58
- /**
59
- * The arrow artwork points RIGHT at rest — the path's tip is authored on the
60
- * left, but `popoverArrow`'s outer `matrix(-1,0,-0,-1,...)` flips it. Verified
61
- * by rasterising the mask: the left edge is ~97% covered (the flat base) and
62
- * the right edge ~4% (the point).
63
- */
64
- export declare const ARROW_NATIVE_DIRECTION: {
65
- x: number;
66
- y: number;
67
- };
68
- /**
69
- * Degrees to rotate the arrow so it points from the chip back at its hitbox.
70
- * CSS rotation is clockwise with y pointing down.
71
- */
72
- export declare function arrowRotationForSide(side: ChipSide): number;