@phuong-tran-redoc/document-engine-angular 0.0.13 → 0.0.15

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm angular](https://img.shields.io/npm/v/@phuong-tran-redoc/document-engine-angular?label=@phuong-tran-redoc/document-engine-angular&color=red)](https://www.npmjs.com/package/@phuong-tran-redoc/document-engine-angular) ![License](https://img.shields.io/npm/l/@phuong-tran-redoc/document-engine-core)
4
4
 
5
- Angular wrapper for [`@phuong-tran-redoc/document-engine-core`](../document-engine-core). This library provides Angular components, directives, and services to integrate the Document Engine into Angular applications.
5
+ Angular wrapper for [`@phuong-tran-redoc/document-engine-core`](https://www.npmjs.com/package/@phuong-tran-redoc/document-engine-core). This library provides Angular components, directives, and services to integrate the Document Engine into Angular applications.
6
6
 
7
7
  ---
8
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phuong-tran-redoc/document-engine-angular",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "type": "commonjs",
5
5
  "license": "MIT",
6
6
  "author": "Duc Phuong (Jack) <tdp99.business@gmail.com>",
@@ -26,37 +26,11 @@
26
26
  "dependencies": {
27
27
  "tslib": "^2.3.0",
28
28
  "@floating-ui/dom": "^1.7.4",
29
- "@tiptap/extension-bubble-menu": "^3.10.5",
30
- "@tiptap/extension-floating-menu": "^3.10.5",
31
- "@tiptap/extension-image": "^3.10.5",
32
- "@tiptap/extension-subscript": "^3.10.5",
33
- "@tiptap/extension-superscript": "^3.10.5",
34
- "@tiptap/extension-text-align": "^3.10.5",
35
- "@tiptap/extension-text-style": "^3.10.5",
36
- "@tiptap/extensions": "^3.10.5",
37
- "@tiptap/extension-blockquote": "^3.10.5",
38
- "@tiptap/extension-bold": "^3.10.5",
39
- "@tiptap/extension-code": "^3.10.5",
40
- "@tiptap/extension-code-block": "^3.10.5",
41
- "@tiptap/extension-document": "^3.10.5",
42
- "@tiptap/extension-hard-break": "^3.10.5",
43
- "@tiptap/extension-horizontal-rule": "^3.10.5",
44
- "@tiptap/extension-italic": "^3.10.5",
45
- "@tiptap/extension-link": "^3.10.5",
46
- "@tiptap/extension-strike": "^3.10.5",
47
- "@tiptap/extension-text": "^3.10.5",
48
- "@tiptap/extension-underline": "^3.10.5",
49
- "@phuong-tran-redoc/document-engine-core": "0.0.13"
29
+ "@phuong-tran-redoc/document-engine-core": "0.0.15"
50
30
  },
51
31
  "peerDependencies": {
52
32
  "rxjs": "^7.5.0",
53
33
  "lodash-es": "^4.17.10",
54
- "@tiptap/core": "^3.10.5",
55
- "@tiptap/pm": "^3.10.5",
56
- "@tiptap/extension-heading": "^3.10.5",
57
- "@tiptap/extension-table": "^3.10.5",
58
- "@tiptap/extension-list": "^3.10.5",
59
- "@tiptap/extension-paragraph": "^3.10.5",
60
34
  "@angular/core": ">=14.0.0 <21.0.0",
61
35
  "@angular/common": ">=14.0.0 <21.0.0",
62
36
  "@angular/forms": ">=14.0.0 <21.0.0",
@@ -0,0 +1,214 @@
1
+ // Button styles translated from React component (button.tsx)
2
+ // Base button styles
3
+ .btn {
4
+ display: inline-flex;
5
+ align-items: center;
6
+ justify-content: center;
7
+ gap: 0.5rem;
8
+ white-space: nowrap;
9
+ border-radius: 0.375rem; // rounded-md
10
+ font-size: 0.875rem; // text-sm (14px)
11
+ font-weight: 500; // font-medium
12
+ transition-property: box-shadow, opacity;
13
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
14
+ transition-duration: 150ms;
15
+ outline: none;
16
+ user-select: none;
17
+ -webkit-tap-highlight-color: transparent;
18
+ cursor: pointer;
19
+
20
+ // Disabled state
21
+ &:disabled,
22
+ &[disabled] {
23
+ pointer-events: none;
24
+ opacity: 0.5;
25
+ }
26
+
27
+ // Focus visible state
28
+ &:focus-visible {
29
+ border-color: var(--ring, hsl(221.2 83.2% 53.3%));
30
+ box-shadow: 0 0 0 3px var(--ring, hsl(221.2 83.2% 53.3% / 0.5));
31
+ }
32
+
33
+ // Aria invalid state
34
+ &[aria-invalid='true'] {
35
+ border-color: var(--destructive, hsl(0 84.2% 60.2%));
36
+ box-shadow: 0 0 0 3px var(--destructive, hsl(0 84.2% 60.2% / 0.2));
37
+ }
38
+
39
+ @media (prefers-color-scheme: dark) {
40
+ &[aria-invalid='true'] {
41
+ box-shadow: 0 0 0 3px var(--destructive, hsl(0 84.2% 60.2% / 0.4));
42
+ }
43
+ }
44
+ }
45
+
46
+ // Variant: default (primary)
47
+ .btn--default {
48
+ background-color: var(--primary, hsl(221.2 83.2% 53.3%));
49
+ color: var(--primary-foreground, hsl(0 0% 100%));
50
+ border: 1px solid transparent;
51
+
52
+ &:hover:not(:disabled) {
53
+ background-color: var(--primary, hsl(221.2 83.2% 53.3% / 0.9));
54
+ }
55
+ }
56
+
57
+ // Variant: destructive
58
+ .btn--destructive {
59
+ background-color: var(--destructive, hsl(0 84.2% 60.2%));
60
+ color: white;
61
+ border: 1px solid transparent;
62
+
63
+ &:hover:not(:disabled) {
64
+ background-color: var(--destructive, hsl(0 84.2% 60.2% / 0.9));
65
+ }
66
+
67
+ &:focus-visible {
68
+ box-shadow: 0 0 0 3px var(--destructive, hsl(0 84.2% 60.2% / 0.2));
69
+ }
70
+
71
+ @media (prefers-color-scheme: dark) {
72
+ background-color: var(--destructive, hsl(0 84.2% 60.2% / 0.6));
73
+
74
+ &:focus-visible {
75
+ box-shadow: 0 0 0 3px var(--destructive, hsl(0 84.2% 60.2% / 0.4));
76
+ }
77
+ }
78
+ }
79
+
80
+ // Variant: outline
81
+ .btn--outline {
82
+ border: 1px solid var(--border, hsl(214.3 31.8% 91.4%));
83
+ background-color: var(--background, hsl(0 0% 100%));
84
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); // shadow-xs
85
+
86
+ &:hover:not(:disabled) {
87
+ background-color: var(--accent, hsl(210 40% 96.1%));
88
+ color: var(--accent-foreground, hsl(222.2 47.4% 11.2%));
89
+ }
90
+
91
+ @media (prefers-color-scheme: dark) {
92
+ background-color: var(--input, hsl(214.3 31.8% 91.4% / 0.3));
93
+ border-color: var(--input, hsl(214.3 31.8% 91.4%));
94
+
95
+ &:hover:not(:disabled) {
96
+ background-color: var(--input, hsl(214.3 31.8% 91.4% / 0.5));
97
+ }
98
+ }
99
+ }
100
+
101
+ // Variant: secondary
102
+ .btn--secondary {
103
+ background-color: var(--secondary, hsl(210 40% 96.1%));
104
+ color: var(--secondary-foreground, hsl(222.2 47.4% 11.2%));
105
+ border: 1px solid transparent;
106
+
107
+ &:hover:not(:disabled) {
108
+ background-color: var(--secondary, hsl(210 40% 96.1% / 0.8));
109
+ }
110
+ }
111
+
112
+ // Variant: ghost
113
+ .btn--ghost {
114
+ background-color: transparent;
115
+ border: 1px solid transparent;
116
+ color: var(--secondary-foreground, hsl(222.2 47.4% 11.2%));
117
+
118
+ &:hover:not(:disabled) {
119
+ background-color: var(--accent, hsl(210 40% 96.1%));
120
+ color: var(--accent-foreground, hsl(222.2 47.4% 11.2%));
121
+ }
122
+
123
+ @media (prefers-color-scheme: dark) {
124
+ &:hover:not(:disabled) {
125
+ background-color: var(--accent, hsl(210 40% 96.1% / 0.5));
126
+ }
127
+ }
128
+ }
129
+
130
+ // Variant: link
131
+ .btn--link {
132
+ background-color: transparent;
133
+ color: var(--primary, hsl(221.2 83.2% 53.3%));
134
+ text-decoration: underline;
135
+ text-underline-offset: 4px;
136
+ border: none;
137
+ padding: 0;
138
+
139
+ &:hover:not(:disabled) {
140
+ text-decoration: underline;
141
+ }
142
+ }
143
+
144
+ // Size: default
145
+ .btn--size-default {
146
+ height: 2.25rem; // h-9 (36px)
147
+ padding: 0.5rem 1rem; // px-4 py-2
148
+
149
+ &:has(> svg) {
150
+ padding-left: 0.75rem; // has-[>svg]:px-3
151
+ padding-right: 0.75rem;
152
+ }
153
+ }
154
+
155
+ // Size: sm
156
+ .btn--size-sm {
157
+ height: 2rem; // h-8 (32px)
158
+ border-radius: 0.375rem; // rounded-md
159
+ gap: 0.375rem; // gap-1.5
160
+ padding: 0.5rem 0.75rem; // px-3
161
+
162
+ &:has(> svg) {
163
+ padding-left: 0.625rem; // has-[>svg]:px-2.5
164
+ padding-right: 0.625rem;
165
+ }
166
+ }
167
+
168
+ // Size: lg
169
+ .btn--size-lg {
170
+ height: 2.5rem; // h-10 (40px)
171
+ border-radius: 0.375rem; // rounded-md
172
+ padding: 0.5rem 1.5rem; // px-6
173
+
174
+ &:has(> svg) {
175
+ padding-left: 1rem; // has-[>svg]:px-4
176
+ padding-right: 1rem;
177
+ }
178
+ }
179
+
180
+ // Size: icon
181
+ .btn--size-icon {
182
+ width: 2.25rem; // size-9 (36px)
183
+ height: 2.25rem;
184
+ padding: 0;
185
+ border-radius: 0.375rem;
186
+
187
+ &:has(> svg) {
188
+ padding: 0;
189
+ }
190
+ }
191
+
192
+ // Size: icon-sm
193
+ .btn--size-icon-sm {
194
+ width: 2rem; // size-8 (32px)
195
+ height: 2rem;
196
+ padding: 0;
197
+ border-radius: 0.375rem;
198
+
199
+ &:has(> svg) {
200
+ padding: 0;
201
+ }
202
+ }
203
+
204
+ // Size: icon-lg
205
+ .btn--size-icon-lg {
206
+ width: 2.5rem; // size-10 (40px)
207
+ height: 2.5rem;
208
+ padding: 0;
209
+ border-radius: 0.375rem;
210
+
211
+ &:has(> svg) {
212
+ padding: 0;
213
+ }
214
+ }
@@ -0,0 +1,67 @@
1
+ .document-engine-checkbox {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ gap: 0.5rem;
5
+ cursor: pointer;
6
+ user-select: none;
7
+ }
8
+
9
+ .document-engine-checkbox__input {
10
+ position: absolute;
11
+ width: 1px;
12
+ height: 1px;
13
+ padding: 0;
14
+ margin: -1px;
15
+ overflow: hidden;
16
+ clip: rect(0, 0, 0, 0);
17
+ white-space: nowrap;
18
+ border-width: 0;
19
+ }
20
+
21
+ .document-engine-checkbox__box {
22
+ display: flex;
23
+ align-items: center;
24
+ justify-content: center;
25
+ width: 1rem;
26
+ height: 1rem;
27
+ border: 1px solid var(--input);
28
+ border-radius: 0.25rem;
29
+ background-color: transparent;
30
+ transition: background-color 0.2s, border-color 0.2s;
31
+
32
+ .document-engine-checkbox__input:checked ~ & {
33
+ background-color: var(--primary);
34
+ border-color: var(--primary);
35
+ }
36
+
37
+ .document-engine-checkbox__input:focus-visible ~ & {
38
+ outline: 2px solid var(--ring);
39
+ outline-offset: 2px;
40
+ }
41
+
42
+ .document-engine-checkbox__input:disabled ~ & {
43
+ cursor: not-allowed;
44
+ opacity: 0.5;
45
+ }
46
+ }
47
+
48
+ .document-engine-checkbox__icon {
49
+ width: 0.75rem;
50
+ height: 0.75rem;
51
+ color: var(--primary-foreground);
52
+ }
53
+
54
+ .document-engine-checkbox__label {
55
+ font-size: 0.875rem;
56
+ line-height: 1;
57
+ font-weight: 500;
58
+
59
+ .document-engine-checkbox__input:disabled ~ & {
60
+ cursor: not-allowed;
61
+ opacity: 0.5;
62
+ }
63
+ }
64
+
65
+ .document-engine-checkbox-container {
66
+ display: inline-block;
67
+ }
@@ -0,0 +1,109 @@
1
+ // Container
2
+ .document-engine-color-picker {
3
+ padding: 0.75rem;
4
+ width: 100%;
5
+ }
6
+
7
+ // Palette grid
8
+ .palette {
9
+ display: grid;
10
+ grid-template-columns: repeat(5, minmax(0, 1fr));
11
+ gap: 0.5rem;
12
+ margin-bottom: 0.75rem;
13
+
14
+ &__item {
15
+ position: relative;
16
+ width: fit-content;
17
+ }
18
+ }
19
+
20
+ // Swatches
21
+ .swatch {
22
+ width: 2.25rem; // w-9
23
+ height: 2.25rem; // h-9
24
+ border-radius: 0.25rem; // rounded
25
+ border: 1px solid var(--border, #e5e7eb); // border-border
26
+ cursor: pointer;
27
+ position: relative;
28
+ overflow: hidden;
29
+ transition: transform 150ms ease;
30
+ background-clip: padding-box;
31
+
32
+ &:hover {
33
+ transform: scale(1.1); // hover:scale-110
34
+ }
35
+
36
+ // Transparent checkerboard overlay
37
+ &__transparent {
38
+ position: absolute;
39
+ inset: 0;
40
+ opacity: 0.3;
41
+ background-image: repeating-conic-gradient(#ccc 0deg 90deg, #fff 90deg 180deg);
42
+ background-size: 6px 6px;
43
+ }
44
+
45
+ // Active indicator button
46
+ &__active-indicator {
47
+ position: absolute;
48
+ top: -0.5rem; // -top-2
49
+ right: -0.5rem; // -right-2
50
+ display: grid; // grid place-items-center
51
+ place-items: center;
52
+ border-radius: 9999px; // rounded-full
53
+ background-color: var(--card, #fff); // bg-card
54
+ border: 1px solid var(--border, #e5e7eb); // border-border
55
+ box-shadow: var(--shadow-elevation-1, 0 1px 2px rgba(0, 0, 0, 0.08)); // shadow-elevation-1
56
+ padding: 0;
57
+ }
58
+ }
59
+
60
+ // Used colors section
61
+ .used {
62
+ margin-bottom: 0.75rem; // mb-3
63
+
64
+ &__label {
65
+ font-size: 0.75rem; // text-xs
66
+ color: var(--muted-foreground, #6b7280); // text-muted-foreground
67
+ margin-bottom: 0.5rem; // mb-2
68
+ }
69
+
70
+ &__list {
71
+ display: flex;
72
+ gap: 0.5rem; // gap-2
73
+ flex-wrap: wrap;
74
+ }
75
+ }
76
+
77
+ // Custom color section
78
+ .custom {
79
+ &__label {
80
+ font-size: 0.75rem; // text-xs
81
+ color: var(--muted-foreground, #6b7280);
82
+ margin-bottom: 0.5rem; // mb-2
83
+ }
84
+
85
+ &__controls {
86
+ display: flex;
87
+ gap: 0.5rem; // gap-2
88
+ align-items: center;
89
+ }
90
+
91
+ &__picker {
92
+ width: 2.25rem; // w-9
93
+ height: 2.25rem; // h-9
94
+ border-radius: 0.25rem; // rounded
95
+ border: 1px solid var(--border, #e5e7eb); // border-border
96
+ cursor: pointer;
97
+ padding: 0; // native color input paddings differ
98
+ }
99
+
100
+ &__hex {
101
+ flex: 1 1 auto; // flex-1
102
+ max-width: 6rem; // max-w-24
103
+ padding: 0.25rem 0.5rem; // px-2 py-1
104
+ font-size: 0.875rem; // text-sm
105
+ border: 1px solid var(--border, #e5e7eb); // border-border
106
+ border-radius: 0.25rem; // rounded
107
+ height: 2.25rem;
108
+ }
109
+ }
@@ -0,0 +1,19 @@
1
+ .document-engine-document-editor {
2
+ display: flex;
3
+ flex-direction: column;
4
+ width: 100%;
5
+ border-radius: 0.75rem;
6
+ // background-color: var(--card, #fff);
7
+ color: var(--card-foreground, #000);
8
+ box-shadow: none;
9
+
10
+ &__content {
11
+ padding: 1rem;
12
+ border: 1px solid var(--border, #e5e7eb);
13
+ }
14
+ }
15
+
16
+ // Only show border-top if toolbar exists as sibling above
17
+ // document-engine-toolbar ~ .document-engine-document-editor__content {
18
+ // border-top: 1px solid var(--border, #e5e7eb);
19
+ // }
@@ -0,0 +1,7 @@
1
+ .document-engine-error-message__text {
2
+ font-size: 0.875rem;
3
+ line-height: 1.25rem;
4
+ color: var(--destructive);
5
+ font-weight: 500;
6
+ margin-top: 0.25rem;
7
+ }
@@ -0,0 +1,40 @@
1
+ .document-engine-document-editor__footer {
2
+ padding: 0.5rem 1rem;
3
+ border: 1px solid var(--border, #e5e7eb);
4
+ border-top: none;
5
+ border-bottom-left-radius: 0.75rem;
6
+ border-bottom-right-radius: 0.75rem;
7
+
8
+ &-content {
9
+ display: flex;
10
+ align-items: center;
11
+ justify-content: space-between;
12
+ gap: 0.5rem;
13
+ }
14
+
15
+ &-left {
16
+ display: flex;
17
+ align-items: center;
18
+ justify-content: flex-start;
19
+ flex: 1;
20
+ gap: 0.5rem;
21
+ }
22
+
23
+ &-right {
24
+ display: flex;
25
+ align-items: center;
26
+ gap: 0.5rem;
27
+ flex-shrink: 0;
28
+ }
29
+
30
+ &-item {
31
+ display: flex;
32
+ align-items: center;
33
+ gap: 0.75rem;
34
+ }
35
+
36
+ &-text {
37
+ font-size: 0.875rem;
38
+ color: var(--muted-foreground, #6b7280);
39
+ }
40
+ }
@@ -0,0 +1,12 @@
1
+ document-engine-icon {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+
6
+ svg {
7
+ width: 20px;
8
+ height: 20px;
9
+ fill: currentColor;
10
+ transition: fill 200ms cubic-bezier(0.4, 0, 0.2, 1);
11
+ }
12
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Main styles entry point for @document-engine/document-engine-angular
3
+ *
4
+ * Usage in client application:
5
+ *
6
+ * Option 1: Import default styles (recommended)
7
+ * In your main styles.scss or styles.css:
8
+ * @import '@document-engine/document-engine-angular/styles';
9
+ *
10
+ * Option 2: Import individual style files
11
+ * @import '@document-engine/document-engine-angular/styles/button';
12
+ * @import '@document-engine/document-engine-angular/styles/icon';
13
+ * @import '@document-engine/document-engine-angular/styles/toolbar';
14
+ * @import '@document-engine/document-engine-angular/styles/document-editor';
15
+ * @import '@document-engine/document-engine-angular/styles/color-picker';
16
+ *
17
+ * Option 3: Provide custom styles
18
+ * Styles use class and element selectors (document-engine-*, .document-engine-*),
19
+ * so you can override them with your own CSS without importing these files.
20
+ */
21
+
22
+ @forward 'icon';
23
+ @forward 'button';
24
+ @forward 'toolbar';
25
+ @forward 'footer';
26
+ @forward 'document-editor';
27
+ @forward 'color-picker';
28
+ @forward 'select';
29
+ @forward 'page-break';
30
+ @forward 'input';
31
+ @forward 'label';
32
+ @forward 'error-message';
33
+ @forward 'checkbox';
34
+ @forward 'toggle-button';
@@ -0,0 +1,62 @@
1
+ .document-engine-input {
2
+ // Base styles
3
+ height: 2.25rem;
4
+ width: 100%;
5
+ min-width: 0;
6
+ border-radius: 0.375rem;
7
+ border: 1px solid var(--input);
8
+ background-color: transparent;
9
+ padding: 0.25rem 0.75rem;
10
+ font-size: 1rem;
11
+ line-height: 1.5rem;
12
+ // box-shadow: var(--shadow-elevation-1);
13
+ transition: color 0.2s, box-shadow 0.2s;
14
+ outline: none;
15
+
16
+ // File input styles
17
+ &::file-selector-button {
18
+ color: var(--foreground);
19
+ background: transparent;
20
+ border: 0;
21
+ padding: 0;
22
+ font-size: 0.875rem;
23
+ font-weight: 500;
24
+ height: 1.75rem;
25
+ display: inline-flex;
26
+ align-items: center;
27
+ }
28
+
29
+ // Placeholder
30
+ &::placeholder {
31
+ color: var(--muted-foreground);
32
+ }
33
+
34
+ // Focus visible
35
+ &:focus-visible {
36
+ border-color: var(--ring);
37
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 50%, transparent);
38
+ }
39
+
40
+ // Disabled
41
+ &:disabled {
42
+ pointer-events: none;
43
+ cursor: not-allowed;
44
+ opacity: 0.5;
45
+ }
46
+
47
+ // Invalid state
48
+ &[aria-invalid='true'] {
49
+ border-color: var(--destructive);
50
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--destructive) 20%, transparent);
51
+
52
+ @media (prefers-color-scheme: dark) {
53
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--destructive) 40%, transparent);
54
+ }
55
+ }
56
+
57
+ // Responsive
58
+ @media (min-width: 768px) {
59
+ font-size: 0.875rem;
60
+ line-height: 1.25rem;
61
+ }
62
+ }
@@ -0,0 +1,23 @@
1
+ .document-engine-label {
2
+ display: flex;
3
+ align-items: center;
4
+ gap: 0.5rem;
5
+ font-size: 0.875rem;
6
+ line-height: 1;
7
+ font-weight: 500;
8
+ user-select: none;
9
+
10
+ // When group has data-disabled="true"
11
+ [data-disabled='true'] &,
12
+ .group[data-disabled='true'] & {
13
+ pointer-events: none;
14
+ opacity: 0.5;
15
+ }
16
+
17
+ // When peer is disabled
18
+ .peer:disabled ~ &,
19
+ :disabled ~ & {
20
+ cursor: not-allowed;
21
+ opacity: 0.5;
22
+ }
23
+ }
@@ -0,0 +1,35 @@
1
+ .document-engine-page-break {
2
+ position: relative;
3
+ margin-top: 1rem;
4
+ margin-bottom: 1rem;
5
+
6
+ border-top-width: 2px;
7
+ border-top-style: dashed;
8
+ border-top-color: var(--document-engine-border, oklch(0.922 0 0));
9
+
10
+ user-select: none;
11
+ }
12
+
13
+ @media print {
14
+ .document-engine-page-break {
15
+ height: 0;
16
+ overflow: hidden;
17
+ border-top: none;
18
+ margin: 0;
19
+ }
20
+ }
21
+
22
+ .document-engine-page-break-label {
23
+ position: absolute;
24
+ top: -0.5rem;
25
+ left: 50%;
26
+ transform: translateX(-50%);
27
+
28
+ background: var(--document-engine-background, oklch(1 0 0));
29
+ color: var(--document-engine-text-muted, oklch(0.556 0 0));
30
+
31
+ padding-left: 0.5rem;
32
+ padding-right: 0.5rem;
33
+ font-size: 0.75rem;
34
+ line-height: 1rem;
35
+ }
@@ -0,0 +1,144 @@
1
+ .document-engine-select {
2
+ position: relative;
3
+ display: inline-block;
4
+ min-width: 3.5rem;
5
+
6
+ &__trigger {
7
+ appearance: none;
8
+ display: inline-flex;
9
+ align-items: center;
10
+ justify-content: space-between;
11
+ gap: 0.25rem;
12
+ // min-width: 4rem;
13
+ // height: 2rem;
14
+ padding: 0.375rem 0.5rem;
15
+ background-color: transparent;
16
+ // border: 1px solid var(--border, #e5e7eb);
17
+ border-radius: 0.375rem;
18
+ font-size: 0.875rem;
19
+ color: var(--foreground, #000);
20
+ cursor: pointer;
21
+ transition: all 0.15s ease;
22
+
23
+ &:hover:not(&--disabled) {
24
+ background-color: var(--accent, #f3f4f6);
25
+ }
26
+
27
+ &:focus {
28
+ outline: none;
29
+ border-color: var(--ring, #3b82f6);
30
+ box-shadow: 0 0 0 1px var(--ring, #3b82f6);
31
+ }
32
+
33
+ &--open {
34
+ border-color: var(--ring, #3b82f6);
35
+ box-shadow: 0 0 0 1px var(--ring, #3b82f6);
36
+ }
37
+
38
+ &--disabled {
39
+ opacity: 0.5;
40
+ cursor: not-allowed;
41
+ }
42
+ }
43
+
44
+ &__value {
45
+ flex: 1;
46
+ text-align: left;
47
+ white-space: nowrap;
48
+ overflow: hidden;
49
+ text-overflow: ellipsis;
50
+ display: flex;
51
+ align-items: center;
52
+ // justify-content: center;
53
+ min-height: 20px;
54
+ }
55
+
56
+ &__icon {
57
+ width: 1rem;
58
+ height: 1rem;
59
+ flex-shrink: 0;
60
+ color: var(--muted-foreground, #9ca3af);
61
+ transition: transform 0.15s ease;
62
+
63
+ .document-engine-select__trigger--open & {
64
+ transform: rotate(180deg);
65
+ }
66
+ }
67
+
68
+ &__dropdown {
69
+ position: absolute;
70
+ z-index: 1000;
71
+ min-width: 3.5rem;
72
+ max-height: 20rem;
73
+ overflow: auto;
74
+ background-color: var(--card, #fff);
75
+ border: 1px solid var(--border, #e5e7eb);
76
+ border-radius: 0.375rem;
77
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
78
+ animation: document-engine-select-dropdown-fade-in 0.15s ease;
79
+ }
80
+
81
+ // &__options {
82
+ // padding: 0.25rem;
83
+ // width: max-content;
84
+ // }
85
+ }
86
+
87
+ // Option styles
88
+ .document-engine-select-option {
89
+ display: flex;
90
+ align-items: center;
91
+ gap: 0.5rem;
92
+
93
+ width: 100%;
94
+ padding: 0.5rem 0.75rem;
95
+ background-color: transparent;
96
+ border: none;
97
+ border-radius: 0.25rem;
98
+ font-size: 0.875rem;
99
+ color: var(--foreground, #000);
100
+ text-align: left;
101
+ cursor: pointer;
102
+ transition: background-color 0.15s ease;
103
+ white-space: nowrap;
104
+
105
+ &:hover:not(&--disabled) {
106
+ background-color: var(--accent, #f3f4f6);
107
+ }
108
+
109
+ &--selected {
110
+ background-color: var(--accent, #f3f4f6);
111
+ font-weight: 500;
112
+ }
113
+
114
+ &--disabled {
115
+ opacity: 0.5;
116
+ cursor: not-allowed;
117
+ }
118
+ }
119
+
120
+ // Outline variant - affects options only
121
+ .document-engine-select--outline {
122
+ width: 100%;
123
+
124
+ .document-engine-select__trigger {
125
+ border: 1px solid var(--border, #e5e7eb);
126
+ width: 100%;
127
+ }
128
+
129
+ .document-engine-select__dropdown {
130
+ width: 100%;
131
+ }
132
+ }
133
+
134
+ // Animation
135
+ @keyframes document-engine-select-dropdown-fade-in {
136
+ from {
137
+ opacity: 0;
138
+ transform: translateY(-4px);
139
+ }
140
+ to {
141
+ opacity: 1;
142
+ transform: translateY(0);
143
+ }
144
+ }
@@ -0,0 +1,53 @@
1
+ .document-engine-toggle-group {
2
+ display: inline-flex;
3
+ border-radius: 0.375rem;
4
+ border: 1px solid var(--border);
5
+ background-color: var(--background);
6
+ overflow: hidden;
7
+ }
8
+
9
+ .document-engine-toggle-option {
10
+ display: inline-flex;
11
+ align-items: center;
12
+ justify-content: center;
13
+ padding: 0.5rem 0.75rem;
14
+ font-size: 0.875rem;
15
+ font-weight: 500;
16
+ color: var(--foreground);
17
+ background-color: transparent;
18
+ border: none;
19
+ border-right: 1px solid var(--border);
20
+ cursor: pointer;
21
+ transition: background-color 0.2s, color 0.2s;
22
+ outline: none;
23
+
24
+ &:last-child {
25
+ border-right: none;
26
+ }
27
+
28
+ &:hover:not(:disabled):not(.document-engine-toggle-option--active) {
29
+ background-color: var(--accent);
30
+ color: var(--accent-foreground);
31
+ }
32
+
33
+ &:focus-visible {
34
+ z-index: 1;
35
+ outline: 2px solid var(--ring);
36
+ outline-offset: -2px;
37
+ }
38
+
39
+ &:disabled {
40
+ cursor: not-allowed;
41
+ opacity: 0.5;
42
+ }
43
+ }
44
+
45
+ .document-engine-toggle-option--active {
46
+ background-color: var(--primary);
47
+ color: var(--primary-foreground);
48
+
49
+ &:hover {
50
+ background-color: var(--primary);
51
+ color: var(--primary-foreground);
52
+ }
53
+ }
@@ -0,0 +1,58 @@
1
+ .document-engine-document-editor__toolbar {
2
+ padding: 0.5rem 1rem;
3
+ background-color: var(--card);
4
+
5
+ border-top-left-radius: 0.75rem;
6
+ border-top-right-radius: 0.75rem;
7
+ border: 1px solid var(--border);
8
+
9
+ &-content {
10
+ display: flex;
11
+ align-items: center;
12
+ justify-content: space-between;
13
+ gap: 0.5rem;
14
+ }
15
+
16
+ &-left {
17
+ display: flex;
18
+ flex-wrap: wrap;
19
+ align-items: center;
20
+ justify-content: flex-start;
21
+ flex: 1;
22
+ gap: 0;
23
+ // max-width: 90%;
24
+ }
25
+
26
+ &-right {
27
+ display: flex;
28
+ align-items: center;
29
+ gap: 0.5rem;
30
+ flex-shrink: 0;
31
+ }
32
+
33
+ &-group {
34
+ display: inline-flex;
35
+ align-items: center;
36
+ gap: 0.5rem;
37
+ flex-shrink: 0;
38
+
39
+ // Auto-add divider after each group (except the last one)
40
+ // Divider appears between groups automatically
41
+ // The divider is positioned with margin to create spacing
42
+ &:not(:last-child)::after {
43
+ content: '';
44
+ width: 1px;
45
+ height: 1.25rem;
46
+ margin-left: 0.5rem;
47
+ margin-right: 1rem;
48
+ background-color: var(--muted-foreground, #9ca3af);
49
+ align-self: center;
50
+ flex-shrink: 0;
51
+ }
52
+ }
53
+
54
+ // Legacy divider class (kept for backward compatibility, but not needed anymore)
55
+ &-divider {
56
+ display: none;
57
+ }
58
+ }