@phuong-tran-redoc/document-engine-angular 0.1.3 → 0.1.5

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/index.d.ts CHANGED
@@ -746,9 +746,14 @@ declare class TiptapFloatingMenuDirective implements OnInit, OnDestroy {
746
746
  *
747
747
  * Usage:
748
748
  * <button #trigger>Open</button>
749
- * <div [popover]="trigger" [isOpen]="isOpen">
749
+ * <div [documentEnginePopover]="trigger" [isOpen]="isOpen">
750
750
  * Content
751
751
  * </div>
752
+ *
753
+ * The host is pinned `position: fixed`, so floating-ui is asked for viewport-
754
+ * relative coordinates (`strategy: 'fixed'`). Omitting the strategy yields
755
+ * offset-parent-relative numbers, which are off by the page's scroll offset
756
+ * once written onto a fixed element.
752
757
  */
753
758
  declare class PopoverDirective implements OnChanges, AfterViewInit, OnDestroy {
754
759
  private elRef;
@@ -756,7 +761,16 @@ declare class PopoverDirective implements OnChanges, AfterViewInit, OnDestroy {
756
761
  /**
757
762
  * The trigger element reference (ElementRef or HTMLElement)
758
763
  */
759
- popover: ElementRef<HTMLElement> | HTMLElement;
764
+ documentEnginePopover?: ElementRef<HTMLElement> | HTMLElement;
765
+ /**
766
+ * The trigger element reference (ElementRef or HTMLElement)
767
+ *
768
+ * @deprecated Use `documentEnginePopover`. `[popover]` collides with the
769
+ * native HTML popover attribute and will be removed in the next major.
770
+ */
771
+ popover?: ElementRef<HTMLElement> | HTMLElement;
772
+ /** The trigger, whichever input supplied it. */
773
+ private get trigger();
760
774
  /**
761
775
  * Whether the popover is open
762
776
  */
@@ -784,9 +798,18 @@ declare class PopoverDirective implements OnChanges, AfterViewInit, OnDestroy {
784
798
  private updateVisibility;
785
799
  private setupFloating;
786
800
  private _setupFloatingInternal;
801
+ /**
802
+ * Position `dropdownEl` against `triggerEl`.
803
+ *
804
+ * `strategy: 'fixed'` is required: the host binding pins this element to
805
+ * `position: fixed`, so the coordinates must be viewport-relative. Without it
806
+ * floating-ui returns offset-parent-relative numbers and the panel lands the
807
+ * page's scroll offset away from its trigger.
808
+ */
809
+ private reposition;
787
810
  private cleanup;
788
811
  static ɵfac: i0.ɵɵFactoryDeclaration<PopoverDirective, never>;
789
- static ɵdir: i0.ɵɵDirectiveDeclaration<PopoverDirective, "[popover]", never, { "popover": { "alias": "popover"; "required": false; }; "isOpen": { "alias": "isOpen"; "required": false; }; "placement": { "alias": "placement"; "required": false; }; "offset": { "alias": "offset"; "required": false; }; "padding": { "alias": "padding"; "required": false; }; }, {}, never, never, true, never>;
812
+ static ɵdir: i0.ɵɵDirectiveDeclaration<PopoverDirective, "[documentEnginePopover], [popover]", never, { "documentEnginePopover": { "alias": "documentEnginePopover"; "required": false; }; "popover": { "alias": "popover"; "required": false; }; "isOpen": { "alias": "isOpen"; "required": false; }; "placement": { "alias": "placement"; "required": false; }; "offset": { "alias": "offset"; "required": false; }; "padding": { "alias": "padding"; "required": false; }; }, {}, never, never, true, never>;
790
813
  }
791
814
 
792
815
  declare const DocumentEngineKit: Extension<DocumentEngineConfig, any>;
@@ -1010,6 +1033,14 @@ declare class SelectComponent implements AfterContentInit, OnChanges, OnDestroy,
1010
1033
  static ɵcmp: i0.ɵɵComponentDeclaration<SelectComponent, "document-engine-select", never, { "value": { "alias": "value"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "labelMode": { "alias": "labelMode"; "required": false; }; "variant": { "alias": "variant"; "required": false; }; }, { "valueChange": "valueChange"; }, ["labelDirectives", "options"], ["[documentEngineSelectLabel]", "*"], true, never>;
1011
1034
  }
1012
1035
 
1036
+ type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
1037
+
1038
+ interface HeadingOption {
1039
+ value: HeadingLevel | null;
1040
+ label: string;
1041
+ class: string;
1042
+ }
1043
+
1013
1044
  interface ToolbarState {
1014
1045
  isReadOnly: boolean;
1015
1046
  canUndo: boolean;
@@ -1067,15 +1098,7 @@ declare class ToolbarComponent implements OnInit, OnDestroy {
1067
1098
  value: TextCaseType;
1068
1099
  label: string;
1069
1100
  }[];
1070
- readonly headingOptions: ({
1071
- value: null;
1072
- label: string;
1073
- class: string;
1074
- } | {
1075
- value: number;
1076
- label: string;
1077
- class: string;
1078
- })[];
1101
+ headingOptions: HeadingOption[];
1079
1102
  readonly textAlignOptions: {
1080
1103
  value: string;
1081
1104
  label: string;
@@ -1105,6 +1128,13 @@ declare class ToolbarComponent implements OnInit, OnDestroy {
1105
1128
  private updateToolbarState;
1106
1129
  ngOnInit(): void;
1107
1130
  ngOnDestroy(): void;
1131
+ /**
1132
+ * Read the configured heading levels off `config.heading`. It may be a boolean
1133
+ * (`true` = default levels, handled by buildHeadingOptions' fallback) or a
1134
+ * `Partial<HeadingOptions>` carrying a `levels` array. Returns undefined when no
1135
+ * explicit levels are set so the caller falls back to the default set.
1136
+ */
1137
+ private resolveHeadingLevels;
1108
1138
  runAndEmit(actionName: string, chain: () => void): void;
1109
1139
  setFontSize(size: string | null): void;
1110
1140
  setLineHeight(lineHeight: string | null): void;
@@ -1270,6 +1300,7 @@ declare class CheckboxComponent implements ControlValueAccessor {
1270
1300
  checked: boolean;
1271
1301
  checkedChange: EventEmitter<boolean>;
1272
1302
  hostClass: boolean;
1303
+ private readonly cdr;
1273
1304
  private onChange;
1274
1305
  private onTouched;
1275
1306
  onCheckboxChange(event: Event): void;
@@ -1296,8 +1327,6 @@ interface DynamicFieldCategory {
1296
1327
  fields: DynamicFieldItem[];
1297
1328
  }
1298
1329
 
1299
- type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
1300
-
1301
1330
  declare const urlValidator: ValidatorFn;
1302
1331
 
1303
1332
  interface LinkAttrs$2 {
@@ -1706,6 +1735,8 @@ declare class ToolbarBubbleMenuComponent implements AfterViewInit, OnDestroy {
1706
1735
  private currentViewRef;
1707
1736
  private currentViewId;
1708
1737
  private currentAttributes;
1738
+ private cleanupAutoUpdate?;
1739
+ private positionTimeout?;
1709
1740
  isVisible: boolean;
1710
1741
  ngAfterViewInit(): void;
1711
1742
  ngOnDestroy(): void;
@@ -1728,6 +1759,21 @@ declare class ToolbarBubbleMenuComponent implements AfterViewInit, OnDestroy {
1728
1759
  private handleNavigateTo;
1729
1760
  private handleGoBack;
1730
1761
  private findViewConfig;
1762
+ /**
1763
+ * Anchor the bubble to its trigger with floating-ui, matching
1764
+ * `PopoverDirective`.
1765
+ *
1766
+ * The hand-rolled version this replaces measured the trigger exactly once, so
1767
+ * scrolling left the panel welded to the viewport while its target slid away.
1768
+ * It also had no third case: a panel that fit neither below nor above got a
1769
+ * negative `top`, putting its own header off the top edge of the screen.
1770
+ * `flip` handles the second placement and `shift` clamps the panel into the
1771
+ * viewport instead, so there is no unhandled case left.
1772
+ *
1773
+ * `strategy: 'fixed'` matches the `position: fixed` written below — asking for
1774
+ * the default `'absolute'` coordinates would offset the panel by the page's
1775
+ * scroll amount.
1776
+ */
1731
1777
  private positionBubble;
1732
1778
  static ɵfac: i0.ɵɵFactoryDeclaration<ToolbarBubbleMenuComponent, never>;
1733
1779
  static ɵcmp: i0.ɵɵComponentDeclaration<ToolbarBubbleMenuComponent, "document-engine-toolbar-bubble-menu", never, { "editor": { "alias": "editor"; "required": false; }; "config": { "alias": "config"; "required": false; }; }, {}, never, never, true, never>;
@@ -1817,4 +1863,4 @@ declare class EditorBubbleMenuComponent implements OnInit, AfterViewInit, OnDest
1817
1863
  }
1818
1864
 
1819
1865
  export { ARCHIVE, ARROW_DROP_DOWN, AngularRenderer, ButtonDirective, CHECK, CLEAR_ALL, CLOSE, CODE, CharacterCountComponent, CheckboxComponent, ColorPickerComponent, ColorPickerViewComponent, DEFAULT, DEFAULT_TOOLBAR_STATE, DESCRIPTION, DYNAMIC_FORM, DocumentEditorComponent, DocumentEditorModule, DocumentEngineKit, DynamicFieldsViewComponent, EDIT, EDITOR_CONTENT_WRAPPER_CLASS, EDITOR_HTML_PREPROCESSOR, EditorBubbleMenuComponent, EditorCapabilities, ErrorMessageComponent, EventManager, FORMAT_ALIGN_CENTER, FORMAT_ALIGN_JUSTIFY, FORMAT_ALIGN_LEFT, FORMAT_ALIGN_RIGHT, FORMAT_BOLD, FORMAT_CLEAR, FORMAT_COLOR_FILL, FORMAT_COLOR_TEXT, FORMAT_INDENT_DECREASE, FORMAT_INDENT_INCREASE, FORMAT_ITALIC, FORMAT_LINE_SPACING, FORMAT_LIST_BULLETED, FORMAT_LIST_NUMBERED, FORMAT_QUOTE, FORMAT_SIZE, FORMAT_STRIKETHROUGH, FORMAT_UNDERLINE, FocusTrapService, FooterComponent, INSERT_PAGE_BREAK, IconComponent, IconRegistryService, ImageInsertViewComponent, InputDirective, LINK, LINK_OFF, LabelDirective, LinkEditViewComponent, LinkMainViewComponent, LinkPropertiesViewComponent, MARKDOWN, MATCH_CASE, PHOTO, PRINT, PopoverDirective, REDO, RESTRICT_EDIT, SEARCH, SEARCH_OFF, SETTINGS, SPECIAL_CHARACTER, SUBSCRIPT, SUPERSCRIPT, SelectComponent, SelectLabelDirective, SelectOptionDirective, SpecialCharactersViewComponent, TABLE_CELL_PROPERTY, TABLE_COLUMN, TABLE_MERGE_CELL, TABLE_PROPERTY, TABLE_ROW, TABLE_ROWS, TableCellStyleViewComponent, TableCreateViewComponent, TableMainViewComponent, TableStyleViewComponent, TemplateViewComponent, TiptapBubbleMenuDirective, TiptapDraggableDirective, TiptapEditorDirective, TiptapFloatingMenuDirective, ToggleGroupComponent, ToggleOptionDirective, ToolbarBubbleMenuComponent, ToolbarComponent, ToolbarService, UNDO, VERTICAL_ALIGN_BOTTOM, VERTICAL_ALIGN_CENTER, VERTICAL_ALIGN_TOP, buildToolbarState, selectionChangeHandler, shouldShowFnFactory, urlValidator };
1820
- export type { BubbleMenuProps, BubbleMenuViewConfig, BubbleMenuViewContent, BubbleTarget, ButtonType, DocumentEngineConfig, DynamicFieldCategory, DynamicFieldItem, EditorBubbleMenuConfig, EditorHtmlPreprocessor, HeadingLevel, IconButton, ImageConfig, ImagePickHook, MediaResult, OutsideHandler, SelectButton, SelectOption, TableCreateViewData, TemplateItem, ToolbarBubbleMenuConfig, ToolbarButton, ToolbarState };
1866
+ export type { BubbleMenuProps, BubbleMenuViewConfig, BubbleMenuViewContent, BubbleTarget, ButtonType, DocumentEngineConfig, DynamicFieldCategory, DynamicFieldItem, EditorBubbleMenuConfig, EditorHtmlPreprocessor, HeadingLevel, HeadingOption, IconButton, ImageConfig, ImagePickHook, MediaResult, OutsideHandler, SelectButton, SelectOption, TableCreateViewData, TemplateItem, ToolbarBubbleMenuConfig, ToolbarButton, ToolbarState };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phuong-tran-redoc/document-engine-angular",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "Realestatedoc (Redoc)",
@@ -35,7 +35,7 @@
35
35
  "dependencies": {
36
36
  "tslib": "^2.3.0",
37
37
  "@floating-ui/dom": "^1.7.4",
38
- "@phuong-tran-redoc/document-engine-core": "0.1.3"
38
+ "@phuong-tran-redoc/document-engine-core": "0.1.5"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "rxjs": "^7.5.0",
@@ -75,6 +75,9 @@
75
75
  "./styles": {
76
76
  "sass": "./src/lib/styles/index.scss"
77
77
  },
78
+ "./styles/tokens": {
79
+ "sass": "./src/lib/styles/tokens.scss"
80
+ },
78
81
  "./styles/editor-content": {
79
82
  "sass": "./src/lib/styles/editor-content.scss"
80
83
  },
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Floating-panel surface — the look every bubble menu / popover panel needs to
3
+ * be legible: an opaque background, a rule, a radius, an elevation and a
4
+ * stacking order.
5
+ *
6
+ * Why this is a mixin and not Tailwind utilities in a template:
7
+ * utilities like `bg-card`, `border-border` or `shadow-elevation-2` only exist
8
+ * if the HOST app's `tailwind.config.js` extends its theme with exactly those
9
+ * keys. The demo app happens to; a consumer with its own theme does not, and
10
+ * there the class names generate no rule at all — the panel then renders as
11
+ * transparent text floating over the page. A component library must not put
12
+ * that requirement on its host, so the panel carries its own surface.
13
+ *
14
+ * Every value resolves from a CSS custom property WITH a fallback, so:
15
+ * - a consumer that remaps the tokens gets its own theme, and
16
+ * - a consumer that remaps nothing still gets a usable, opaque panel.
17
+ *
18
+ * Tokens read here (all optional, all documented in docs/THEMING.md):
19
+ * --popover / --card panel background
20
+ * --popover-foreground / --card-foreground panel text
21
+ * --border panel rule
22
+ * --shadow-elevation-2 panel elevation
23
+ */
24
+
25
+ /* Light-mode floors, used only when the consumer defines nothing. */
26
+ $de-fallback-surface: hsl(0 0% 100%) !default;
27
+ $de-fallback-surface-foreground: hsl(222.2 84% 4.9%) !default;
28
+ $de-fallback-border: hsl(214.3 31.8% 91.4%) !default;
29
+
30
+ @mixin panel-surface($z-index: 30, $radius: 0.25rem) {
31
+ box-sizing: border-box;
32
+ z-index: $z-index;
33
+ border-radius: $radius;
34
+ border: 1px solid var(--border, #{$de-fallback-border});
35
+
36
+ /* `--popover` is the semantic token for a floating surface; `--card` is the
37
+ * broader surface token most consumers already define, so it is the second
38
+ * chance before the hardcoded floor. */
39
+ background-color: var(--popover, var(--card, #{$de-fallback-surface}));
40
+ color: var(--popover-foreground, var(--card-foreground, #{$de-fallback-surface-foreground}));
41
+
42
+ box-shadow: var(--shadow-elevation-2, 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1));
43
+ }
@@ -7,10 +7,31 @@
7
7
  color: var(--card-foreground, #000);
8
8
  box-shadow: none;
9
9
 
10
+ // Participate in a parent that has a real height (a fixed-height container, a
11
+ // flex/grid cell) instead of only ever sizing to content. `flex: 1 1 auto` is
12
+ // what actually claims that height: without it this box stays content-sized as
13
+ // a flex item of :host, and a fixed-height container is left with a band of
14
+ // dead, unclickable space under the editable.
15
+ //
16
+ // `max-height: 100%` is inert when the parent's height is indefinite (a
17
+ // percentage against an auto height resolves to none), so an unconstrained
18
+ // consumer still gets a box that simply grows.
19
+ flex: 1 1 auto;
20
+ min-height: 0;
21
+ max-height: 100%;
22
+
10
23
  &__content {
11
24
  padding: 1rem;
12
25
  border: 1px solid var(--border, #e5e7eb);
13
26
  background-color: var(--card, #fff);
27
+
28
+ // Take the leftover space so the editing surface below can stretch into it.
29
+ // Deliberately no `overflow` here: the panels rendered inside carry selects
30
+ // and colour popovers, and an overflow ancestor can clip them.
31
+ display: flex;
32
+ flex-direction: column;
33
+ flex: 1 1 auto;
34
+ min-height: 0;
14
35
  }
15
36
  }
16
37
 
@@ -18,3 +39,43 @@
18
39
  // document-engine-toolbar ~ .document-engine-document-editor__content {
19
40
  // border-top: 1px solid var(--border, #e5e7eb);
20
41
  // }
42
+
43
+ /**
44
+ * Editing-surface sizing.
45
+ *
46
+ * The library used to size the contenteditable to its content and nothing else,
47
+ * so an emptied editor collapsed to a single line. In a fixed-height container
48
+ * that left a ~28px editable inside a ~480px box that plainly looks like a text
49
+ * field, and clicking anywhere but that one line did nothing.
50
+ *
51
+ * Two hooks, one rule:
52
+ * - `--de-editor-min-height` is the floor (default `12rem`). Remap it, or set
53
+ * it to `0` to opt out entirely.
54
+ * - `flex: 1 1 auto` lets an ancestor with a real height drive the surface, so
55
+ * the editable fills a fixed-height container without any magic number.
56
+ *
57
+ * `.tiptap-editor` is the class `TiptapEditorDirective` puts on its host;
58
+ * `.tiptap` / `.ProseMirror` is the contenteditable Tiptap creates inside it.
59
+ */
60
+ .tiptap-editor {
61
+ display: flex;
62
+ flex-direction: column;
63
+ flex: 1 1 auto;
64
+ min-height: 0;
65
+
66
+ // The editing surface is the scroll container. Without this, `max-height: 100%`
67
+ // above caps the wrapper while nothing scrolls, so a long document paints
68
+ // straight through the bottom of a fixed-height container and over whatever
69
+ // follows it on the page.
70
+ //
71
+ // Safe to put overflow here: the floating panels are rendered inside
72
+ // `document-engine-toolbar`, a sibling of the content box, never a descendant
73
+ // of this element — so there is nothing of theirs for this to clip.
74
+ overflow-y: auto;
75
+
76
+ > .tiptap,
77
+ > .ProseMirror {
78
+ flex: 1 1 auto;
79
+ min-height: var(--de-editor-min-height, 12rem);
80
+ }
81
+ }
@@ -23,8 +23,16 @@
23
23
  *
24
24
  * All styles use class/element selectors and CSS-variable-driven values, so you
25
25
  * can also override them with your own CSS without importing these files.
26
+ *
27
+ * Theming: this barrel also ships zero-specificity DEFAULTS for every custom
28
+ * property the library reads (`_tokens.scss`, emitted on `:where(:root)`), so it
29
+ * looks right out of the box and any token you declare yourself wins without a
30
+ * specificity fight. The full list is in `docs/THEMING.md`.
26
31
  */
27
32
 
33
+ // Token defaults first, so they sit at the top of the emitted sheet.
34
+ @use 'tokens';
35
+
28
36
  @forward 'icon';
29
37
  @forward 'button';
30
38
  @forward 'toolbar';
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Default values for every CSS custom property the library's CSS reads.
3
+ *
4
+ * The library's stylesheets are token-driven: they paint with `var(--border)`,
5
+ * `var(--popover)`, `var(--foreground)` and friends. Historically the library
6
+ * *consumed* those tokens without ever defining or documenting them, so a
7
+ * consumer that had not happened to declare the same shadcn-style token set got
8
+ * panels with no background and text with no colour.
9
+ *
10
+ * This file closes that hole: it declares a light-mode default for every token,
11
+ * so importing the chrome barrel is enough to get a working look with zero
12
+ * theming. See `docs/THEMING.md` for the full contract.
13
+ *
14
+ * ## Why `:where(:root)`
15
+ *
16
+ * `:where()` contributes **zero specificity**, so ANY declaration a consumer
17
+ * writes — `:root { --border: … }`, `.dark { --border: … }`, an inline style,
18
+ * a `[data-theme]` block — beats these defaults regardless of source order.
19
+ * They are a floor, never a fight.
20
+ *
21
+ * ## Rescoping
22
+ *
23
+ * The defaults are also exposed as a mixin, so you can plant a fresh set on any
24
+ * container — e.g. an embedded editor that must ignore the surrounding theme:
25
+ *
26
+ * @use '@phuong-tran-redoc/document-engine-angular/styles/tokens' as de-tokens;
27
+ * .my-isolated-editor { @include de-tokens.token-defaults; }
28
+ */
29
+
30
+ @mixin token-defaults {
31
+ /* --- Surfaces --- */
32
+ --background: hsl(0 0% 100%);
33
+ --foreground: hsl(222.2 84% 4.9%);
34
+ --card: hsl(0 0% 100%);
35
+ --card-foreground: hsl(222.2 84% 4.9%);
36
+ --popover: hsl(0 0% 100%);
37
+ --popover-foreground: hsl(222.2 84% 4.9%);
38
+
39
+ /* --- Accents & state --- */
40
+ --primary: hsl(222.2 47.4% 11.2%);
41
+ --primary-foreground: hsl(210 40% 98%);
42
+ --secondary: hsl(210 40% 96.1%);
43
+ --secondary-foreground: hsl(222.2 47.4% 11.2%);
44
+ --muted: hsl(210 40% 96.1%);
45
+ --muted-foreground: hsl(215.4 16.3% 46.9%);
46
+ --accent: hsl(210 40% 96.1%);
47
+ --accent-foreground: hsl(222.2 47.4% 11.2%);
48
+ --destructive: hsl(0 84.2% 60.2%);
49
+ --destructive-foreground: hsl(210 40% 98%);
50
+
51
+ /* --- Lines --- */
52
+ --border: hsl(214.3 31.8% 91.4%);
53
+ --input: hsl(214.3 31.8% 91.4%);
54
+ --ring: hsl(222.2 84% 4.9%);
55
+
56
+ /* --- Elevation ---
57
+ * Consumed by panels, dropdowns and inputs. Undefined, `box-shadow: var(…)`
58
+ * resolves to nothing, which is how floating panels lost their elevation. */
59
+ --shadow-elevation-1: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
60
+ --shadow-elevation-2: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
61
+ --shadow-elevation-3: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
62
+
63
+ /* --- Editing surface sizing (see docs/THEMING.md#sizing) --- */
64
+ --de-editor-min-height: 12rem;
65
+ }
66
+
67
+ :where(:root) {
68
+ @include token-defaults;
69
+ }