@omnitend/dashboard-for-laravel 0.45.0 → 0.47.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/assets/IBMPlexSans-Bold-Latin1-914f1400.woff2 +0 -0
- package/dist/assets/IBMPlexSans-Medium-Latin1-b5610af0.woff2 +0 -0
- package/dist/assets/IBMPlexSans-Regular-Latin1-b5ad7bd3.woff2 +0 -0
- package/dist/assets/IBMPlexSans-SemiBold-Latin1-fff0ab3a.woff2 +0 -0
- package/dist/components/base/DFormFile.vue.d.ts +17 -0
- package/dist/components/base/DFormValidFeedback.vue.d.ts +12 -0
- package/dist/components/extended/DXDashboard.vue.d.ts +95 -111
- package/dist/components/extended/DXDashboardNavbar.vue.d.ts +2 -36
- package/dist/components/extended/DXDashboardSidebar.vue.d.ts +60 -79
- package/dist/components/extended/DXField.vue.d.ts +16 -0
- package/dist/components/extended/DXTable.vue.d.ts +10 -1
- package/dist/components/extended/DXTableEditorModal.vue.d.ts +13 -3
- package/dist/dashboard-for-laravel.js +11767 -11479
- package/dist/dashboard-for-laravel.js.map +1 -1
- package/dist/dashboard-for-laravel.umd.cjs +7 -7
- package/dist/dashboard-for-laravel.umd.cjs.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/style.css +2 -2
- package/dist/types/index.d.ts +60 -0
- package/dist/types/navigation.d.ts +153 -3
- package/dist/utils/formErrorTargets.d.ts +6 -2
- package/dist/utils/formSchema.d.ts +16 -0
- package/dist/utils/statCardFit.d.ts +19 -0
- package/docs/public/api-reference.json +171 -9
- package/docs/public/docs-map.md +4 -2
- package/docs/public/llms.txt +4 -2
- package/package.json +3 -2
- package/resources/css/theme.scss +339 -4
- package/resources/fonts/ibm-plex-sans/IBMPlexSans-Bold-Latin1.woff2 +0 -0
- package/resources/fonts/ibm-plex-sans/IBMPlexSans-Medium-Latin1.woff2 +0 -0
- package/resources/fonts/ibm-plex-sans/IBMPlexSans-Regular-Latin1.woff2 +0 -0
- package/resources/fonts/ibm-plex-sans/IBMPlexSans-SemiBold-Latin1.woff2 +0 -0
- package/resources/fonts/ibm-plex-sans/OFL.txt +93 -0
- package/resources/fonts/ibm-plex-sans/SOURCE.txt +18 -0
- package/resources/js/components/base/DFormFile.vue +103 -0
- package/resources/js/components/base/DFormValidFeedback.vue +16 -0
- package/resources/js/components/extended/DXDashboard.vue +41 -18
- package/resources/js/components/extended/DXDashboardNavbar.vue +9 -1
- package/resources/js/components/extended/DXDashboardSidebar.vue +25 -3
- package/resources/js/components/extended/DXField.vue +86 -23
- package/resources/js/components/extended/DXFormField.vue +3 -1
- package/resources/js/components/extended/DXStatCard.vue +154 -11
- package/resources/js/components/extended/DXTable.vue +62 -6
- package/resources/js/components/extended/DXTableEditorModal.vue +35 -2
- package/resources/js/composables/useResourceEditor.ts +64 -26
- package/resources/js/index.ts +11 -0
- package/resources/js/types/index.ts +64 -0
- package/resources/js/types/navigation.ts +175 -3
- package/resources/js/utils/formErrorTargets.ts +28 -2
- package/resources/js/utils/formSchema.ts +27 -0
- package/resources/js/utils/statCardFit.ts +210 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omnitend/dashboard-for-laravel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0",
|
|
4
4
|
"description": "Vue 3 dashboard components for Laravel with Bootstrap Vue Next",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/dashboard-for-laravel.umd.cjs",
|
|
@@ -36,13 +36,14 @@
|
|
|
36
36
|
"dev": "vite build --watch",
|
|
37
37
|
"build:lib": "vite build && vite build --config vite.config.charts.ts && node scripts/extract-icon-font.mjs",
|
|
38
38
|
"build": "npm run build:lib && vue-tsc --declaration --emitDeclarationOnly --outDir dist",
|
|
39
|
-
"typecheck": "vue-tsc --noEmit",
|
|
39
|
+
"typecheck": "vue-tsc --noEmit && vue-tsc --noEmit -p tests/types/tsconfig.json",
|
|
40
40
|
"pretest": "npm run build:lib",
|
|
41
41
|
"test": "vitest",
|
|
42
42
|
"pretest:ui": "npm run build:lib",
|
|
43
43
|
"test:ui": "vitest --ui",
|
|
44
44
|
"pretest:headless": "npm run build:lib",
|
|
45
45
|
"test:headless": "vitest --run --browser.headless",
|
|
46
|
+
"test:linux": "bash scripts/test-linux.sh",
|
|
46
47
|
"docs:dev": "astro dev",
|
|
47
48
|
"docs:build": "npm run docs:generate:ai && astro build && node scripts/check-docs-base-links.mjs",
|
|
48
49
|
"docs:preview": "astro preview",
|
package/resources/css/theme.scss
CHANGED
|
@@ -53,8 +53,9 @@ $color-contrast-light: #fff; // Light text color (for dark backgrounds)
|
|
|
53
53
|
// Two bundled typefaces (SIL OFL 1.1; woff2 + licence in resources/fonts/):
|
|
54
54
|
// MAVEN PRO for body text, and POPPINS as the DISPLAY face, published as
|
|
55
55
|
// `--dx-font-family-display`. The theme applies the display face to h1–h4 and
|
|
56
|
-
// nothing else; consumers use the token for things like product names.
|
|
57
|
-
//
|
|
56
|
+
// nothing else; consumers use the token for things like product names. A
|
|
57
|
+
// third, IBM PLEX SANS, supplies DIGITS ONLY for tabular figures (#215; see
|
|
58
|
+
// "Tabular figures" below). All are declared with `@font-face` below, so they render on every machine, not
|
|
58
59
|
// only where the font happens to be installed (the theme used to name Poppins
|
|
59
60
|
// and ship no face for it, so most visitors got the generic sans-serif).
|
|
60
61
|
$font-family-sans-serif: "Maven Pro", system-ui, -apple-system, "Segoe UI", Roboto,
|
|
@@ -62,6 +63,12 @@ $font-family-sans-serif: "Maven Pro", system-ui, -apple-system, "Segoe UI", Robo
|
|
|
62
63
|
$dx-font-family-display: "Poppins", system-ui, -apple-system, "Segoe UI", Roboto,
|
|
63
64
|
"Helvetica Neue", Arial, sans-serif;
|
|
64
65
|
$headings-font-family: var(--dx-font-family-display);
|
|
66
|
+
// The face(s) tabular figures are set in, published as
|
|
67
|
+
// `--dx-font-family-figures`. Only the figures face goes here: the theme
|
|
68
|
+
// appends the surrounding face as the fallback (the body face, or the display
|
|
69
|
+
// face in h1–h4), which is where `£`, `,`, `.` and letters come from. See
|
|
70
|
+
// "Tabular figures" below.
|
|
71
|
+
$dx-font-family-figures: "DX Figures" !default;
|
|
65
72
|
$font-size-base: 1rem; // 16px — the default tier. Legacy omnitend rendered body
|
|
66
73
|
// and table text at 16px; the earlier 0.875rem (14px) shrank every ported page's
|
|
67
74
|
// text ~12% while rem-fixed chrome stayed put, so controls read oversized and
|
|
@@ -128,7 +135,11 @@ $input-padding-y-lg: $btn-padding-y-lg;
|
|
|
128
135
|
$input-border-radius: $border-radius;
|
|
129
136
|
$input-border-color: #d1d5db; // Gray-300
|
|
130
137
|
$input-focus-border-color: $primary;
|
|
131
|
-
|
|
138
|
+
// The focus halo is the brand navy, faint, outside the navy focus border. (It
|
|
139
|
+
// was a leftover indigo from before the navy brand.) Selects take the same
|
|
140
|
+
// ring; Bootstrap gives them their own 0.25rem one at 25%.
|
|
141
|
+
$input-focus-box-shadow: 0 0 0 3px rgba($primary, 0.1);
|
|
142
|
+
$form-select-focus-box-shadow: $input-focus-box-shadow;
|
|
132
143
|
|
|
133
144
|
// Check/radio inputs default their border to `$border-color` (Gray-200), not
|
|
134
145
|
// `$input-border-color` — so a bare checkbox looks faint beside the (darker,
|
|
@@ -441,6 +452,29 @@ $utilities-border-subtle: map.merge(
|
|
|
441
452
|
("pending-subtle": var(--bs-pending-border-subtle))
|
|
442
453
|
);
|
|
443
454
|
|
|
455
|
+
// An invalid control's focus ring is the crimson form-error colour, like its
|
|
456
|
+
// border. Bootstrap builds it from `--bs-danger-rgb`, which is the magenta
|
|
457
|
+
// badge hue here. Its geometry and opacity stay Bootstrap's. The
|
|
458
|
+
// `.invalid-tooltip` background likewise (Bootstrap's is `var(--bs-danger)`):
|
|
459
|
+
// white on #c8102e is 5.9:1. A solid Sass colour, not
|
|
460
|
+
// `--bs-form-invalid-color`, which is a light pink in dark mode where the
|
|
461
|
+
// white text would fail. (The `.form-range` thumb's red is bootstrap-vue-next's
|
|
462
|
+
// own and is left alone.) The map only exists once Bootstrap's variables are
|
|
463
|
+
// read, hence here.
|
|
464
|
+
$form-validation-states: map.merge(
|
|
465
|
+
$form-validation-states,
|
|
466
|
+
(
|
|
467
|
+
"invalid": map.merge(
|
|
468
|
+
map.get($form-validation-states, "invalid"),
|
|
469
|
+
(
|
|
470
|
+
"focus-box-shadow": 0 0 $input-btn-focus-blur $input-focus-width
|
|
471
|
+
rgba($dx-form-error, $input-btn-focus-color-opacity),
|
|
472
|
+
"tooltip-bg-color": $dx-form-error,
|
|
473
|
+
)
|
|
474
|
+
),
|
|
475
|
+
)
|
|
476
|
+
);
|
|
477
|
+
|
|
444
478
|
@import "bootstrap/scss/bootstrap";
|
|
445
479
|
|
|
446
480
|
// ----------------------------------------------------------------------------
|
|
@@ -506,8 +540,42 @@ $dx-bundled-fonts: (
|
|
|
506
540
|
}
|
|
507
541
|
}
|
|
508
542
|
|
|
543
|
+
// DX Figures: IBM Plex Sans's DIGITS, for tabular figures (#215). Maven Pro
|
|
544
|
+
// and Poppins have no `tnum` feature, so `tabular-nums` did nothing in them;
|
|
545
|
+
// Plex Sans's figures are tabular by default. `unicode-range` limits each face
|
|
546
|
+
// to U+0030–0039, so only the digits come from Plex and everything else in a
|
|
547
|
+
// tabular run falls through to the next family in the stack. `size-adjust`
|
|
548
|
+
// matches Plex's figure height (0.710em) to Maven Pro's (0.673em), so a digit
|
|
549
|
+
// sits beside Maven Pro text at the same size. 400 for body text and inputs,
|
|
550
|
+
// 500 for table headers and `.fw-medium`, 600 for `.fw-semibold` (without it
|
|
551
|
+
// font matching takes the 700 face for a 600 request), 700 for DXStatCard's
|
|
552
|
+
// value and `.fw-bold`. The files are IBM's own Latin1 split woff2s, byte-identical to
|
|
553
|
+
// the upstream package (resources/fonts/ibm-plex-sans/SOURCE.txt): "Plex" is a
|
|
554
|
+
// Reserved Font Name, so they must never be subset or re-encoded. Extracted to
|
|
555
|
+
// `dist/assets/` like the faces above, and fetched only where a tabular digit
|
|
556
|
+
// renders.
|
|
557
|
+
$dx-figures-fonts: (
|
|
558
|
+
(400, "ibm-plex-sans/IBMPlexSans-Regular-Latin1"),
|
|
559
|
+
(500, "ibm-plex-sans/IBMPlexSans-Medium-Latin1"),
|
|
560
|
+
(600, "ibm-plex-sans/IBMPlexSans-SemiBold-Latin1"),
|
|
561
|
+
(700, "ibm-plex-sans/IBMPlexSans-Bold-Latin1"),
|
|
562
|
+
);
|
|
563
|
+
|
|
564
|
+
@each $weight, $file in $dx-figures-fonts {
|
|
565
|
+
@font-face {
|
|
566
|
+
font-family: "DX Figures";
|
|
567
|
+
font-style: normal;
|
|
568
|
+
font-weight: $weight;
|
|
569
|
+
font-display: swap;
|
|
570
|
+
src: url("../fonts/#{$file}.woff2") format("woff2");
|
|
571
|
+
unicode-range: U+0030-0039;
|
|
572
|
+
size-adjust: 94.8%;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
509
576
|
:root {
|
|
510
577
|
--dx-font-family-display: #{$dx-font-family-display};
|
|
578
|
+
--dx-font-family-figures: #{$dx-font-family-figures};
|
|
511
579
|
}
|
|
512
580
|
|
|
513
581
|
// Bootstrap gives `$headings-font-family` to h1–h6; the display face is for
|
|
@@ -733,6 +801,147 @@ $dx-display-only-row: '.dx-form--horizontal .row:has(> .col-form-label):not(:has
|
|
|
733
801
|
flex-wrap: nowrap;
|
|
734
802
|
}
|
|
735
803
|
|
|
804
|
+
// DFormFile: bvn's BFormFile draws its own control (`.b-form-file-control`, a
|
|
805
|
+
// div around a Browse button and the file-name text), not a `.form-control`,
|
|
806
|
+
// so none of the theme's input variables reach it. Give it the input's border
|
|
807
|
+
// colour, padding (so its height) and focus ring, and the theme's crimson invalid
|
|
808
|
+
// state (bvn hardcodes Bootstrap's red icon, and the navy focus border took
|
|
809
|
+
// over an invalid control). The state rings come from Bootstrap's own
|
|
810
|
+
// `$form-validation-states`, so they stay identical to `.form-control`'s. Global:
|
|
811
|
+
// the control is inside a bvn root (see CLAUDE.md, scope-id trap).
|
|
812
|
+
.b-form-file-control {
|
|
813
|
+
border-color: var(--d-input-border-color);
|
|
814
|
+
|
|
815
|
+
.b-form-file-text,
|
|
816
|
+
.b-form-file-button {
|
|
817
|
+
padding: $input-padding-y $input-padding-x;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
&.form-control-sm .b-form-file-text,
|
|
821
|
+
&.form-control-sm .b-form-file-button {
|
|
822
|
+
padding: $input-padding-y-sm $input-padding-x-sm;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
&.form-control-lg .b-form-file-text,
|
|
826
|
+
&.form-control-lg .b-form-file-button {
|
|
827
|
+
padding: $input-padding-y-lg $input-padding-x-lg;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
.b-form-file-button {
|
|
831
|
+
border-right-color: var(--d-input-border-color);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
&:focus-within:not([aria-disabled="true"]) {
|
|
835
|
+
border-color: $input-focus-border-color;
|
|
836
|
+
box-shadow: $input-focus-box-shadow;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
&.is-invalid {
|
|
840
|
+
border-color: var(--bs-form-invalid-border-color);
|
|
841
|
+
background-image: escape-svg($form-feedback-icon-invalid);
|
|
842
|
+
|
|
843
|
+
&:focus-within:not([aria-disabled="true"]) {
|
|
844
|
+
border-color: var(--bs-form-invalid-border-color);
|
|
845
|
+
box-shadow: map-get(map-get($form-validation-states, "invalid"), "focus-box-shadow");
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
&.is-valid {
|
|
850
|
+
border-color: var(--bs-form-valid-border-color);
|
|
851
|
+
background-image: escape-svg($form-feedback-icon-valid);
|
|
852
|
+
|
|
853
|
+
&:focus-within:not([aria-disabled="true"]) {
|
|
854
|
+
border-color: var(--bs-form-valid-border-color);
|
|
855
|
+
box-shadow: map-get(map-get($form-validation-states, "valid"), "focus-box-shadow");
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// A disabled fieldset (any disabled DFormGroup: it always renders one) disables
|
|
861
|
+
// the button and the native input but not bvn's `disabled` prop, so give the
|
|
862
|
+
// control the same look as `disabled` (bvn's `[aria-disabled=true]` rule).
|
|
863
|
+
fieldset:disabled .b-form-file-control {
|
|
864
|
+
background-color: var(--bs-secondary-bg);
|
|
865
|
+
opacity: 0.65;
|
|
866
|
+
cursor: not-allowed;
|
|
867
|
+
|
|
868
|
+
.b-form-file-text,
|
|
869
|
+
.b-form-file-button {
|
|
870
|
+
pointer-events: none;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// The state class sits on `.b-form-file-control` (or the plain input), deep
|
|
875
|
+
// inside `.b-form-file-root`, where Bootstrap's `.is-invalid ~ .invalid-feedback`
|
|
876
|
+
// cannot see it; a sibling DFormInvalidFeedback/DFormValidFeedback stayed hidden.
|
|
877
|
+
// `:has()` covers the custom control and `plain` without touching attrs.
|
|
878
|
+
.b-form-file-root:has(> .b-form-file-wrapper > .b-form-file-control.is-invalid, > input.is-invalid) {
|
|
879
|
+
~ .invalid-feedback,
|
|
880
|
+
~ .invalid-tooltip {
|
|
881
|
+
display: block;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
.b-form-file-root:has(> .b-form-file-wrapper > .b-form-file-control.is-valid, > input.is-valid) {
|
|
886
|
+
~ .valid-feedback,
|
|
887
|
+
~ .valid-tooltip {
|
|
888
|
+
display: block;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// In a DInputGroup Bootstrap squares the corners of the radius-less root, not
|
|
893
|
+
// the control inside it, so the control kept a rounded edge against the addon.
|
|
894
|
+
.input-group > .b-form-file-root {
|
|
895
|
+
position: relative;
|
|
896
|
+
|
|
897
|
+
&:focus-within {
|
|
898
|
+
z-index: 5;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
&:not(:first-child) {
|
|
902
|
+
.b-form-file-control,
|
|
903
|
+
.b-form-file-button {
|
|
904
|
+
border-top-left-radius: 0;
|
|
905
|
+
border-bottom-left-radius: 0;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
.input-group:not(.has-validation) > .b-form-file-root:not(:last-child),
|
|
911
|
+
.input-group.has-validation > .b-form-file-root:nth-last-child(n + 3) {
|
|
912
|
+
.b-form-file-control {
|
|
913
|
+
border-top-right-radius: 0;
|
|
914
|
+
border-bottom-right-radius: 0;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
// Drag state. bvn colours the overlay text, its dashed border and the control's
|
|
919
|
+
// border with `--bs-primary` (the brand navy), which is about 1.07:1 on the
|
|
920
|
+
// dark-mode overlay, so the accent is a token that becomes the emphasis colour
|
|
921
|
+
// in dark mode. The overlay's white is hardcoded in bvn; follow the page
|
|
922
|
+
// background.
|
|
923
|
+
:root,
|
|
924
|
+
[data-bs-theme="light"] {
|
|
925
|
+
--dx-form-file-drag-color: var(--bs-primary);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
[data-bs-theme="dark"] {
|
|
929
|
+
--dx-form-file-drag-color: var(--bs-emphasis-color);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
.b-form-file-dragging .b-form-file-control {
|
|
933
|
+
border-color: var(--dx-form-file-drag-color);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
.b-form-file-drag-overlay {
|
|
937
|
+
background-color: rgba(var(--bs-body-bg-rgb), 0.95);
|
|
938
|
+
border-color: var(--dx-form-file-drag-color);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
.b-form-file-drag-text {
|
|
942
|
+
color: var(--dx-form-file-drag-color);
|
|
943
|
+
}
|
|
944
|
+
|
|
736
945
|
// DXNumberStepper: `[ − ][ 12 ][ + ]`. The buttons are DButton icon-only
|
|
737
946
|
// squares, sized by the input group. The number is centred between them, and
|
|
738
947
|
// the browser's spin arrows are hidden (they duplicate the buttons and push the
|
|
@@ -1388,6 +1597,128 @@ aside.dashboard-sidebar--light {
|
|
|
1388
1597
|
// wrapper's DIRECT child table is affected, so a table nested in a cell keeps
|
|
1389
1598
|
// its own layout.
|
|
1390
1599
|
|
|
1600
|
+
// ----------------------------------------------------------------------------
|
|
1601
|
+
// Tabular figures (#215)
|
|
1602
|
+
// ----------------------------------------------------------------------------
|
|
1603
|
+
//
|
|
1604
|
+
// Every digit on the same advance, so amounts in a column (or a total that
|
|
1605
|
+
// updates in place) line up and do not jitter. Global, so consumer markup and
|
|
1606
|
+
// slot content can use it; DXTable's `tabular: true` field option adds it to
|
|
1607
|
+
// a column's cells, and DXStatCard's value and DXCurrencyInput's amount use
|
|
1608
|
+
// tabular figures by default.
|
|
1609
|
+
//
|
|
1610
|
+
// Maven Pro and Poppins have no `tnum` feature, so the digits come from the
|
|
1611
|
+
// `--dx-font-family-figures` token (DX Figures, IBM Plex Sans digits, above),
|
|
1612
|
+
// with the surrounding face as the fallback for everything else. `tabular-nums`
|
|
1613
|
+
// stays, so a consumer who points the token at a face with a `tnum` feature
|
|
1614
|
+
// (Inter, IBM Plex Mono) still gets tabular figures from it. Setting the token
|
|
1615
|
+
// to `initial` turns the face off: the declaration becomes invalid and the
|
|
1616
|
+
// element inherits its parent's family.
|
|
1617
|
+
//
|
|
1618
|
+
// Heading trap: h1–h4 are in the display face, and `.dx-tabular` outranks
|
|
1619
|
+
// `h1`, so in or on a heading the fallback must be the display face too, or
|
|
1620
|
+
// the heading's letters would turn into Maven Pro. The second rule does that.
|
|
1621
|
+
// Elsewhere the fallback is the body face: CSS cannot say "the inherited
|
|
1622
|
+
// face" inside a font list, so a `.dx-tabular` inside some other display-face
|
|
1623
|
+
// element (the sidebar) gets body-face letters. The same trap in or on
|
|
1624
|
+
// `code`, `kbd`, `samp` and `pre`: their fallback is the monospace face, so a
|
|
1625
|
+
// code sample keeps monospace letters (the third rule, which comes last so
|
|
1626
|
+
// code inside a heading stays monospace). Both context rules use `:where()`
|
|
1627
|
+
// so each has exactly `.dx-tabular`'s specificity and wins by source order.
|
|
1628
|
+
// Pinned by tabular-figures.test.ts and theme-fonts.test.ts.
|
|
1629
|
+
$dx-headings-1-4: "h1, h2, h3, h4, .h1, .h2, .h3, .h4";
|
|
1630
|
+
$dx-monospace-elements: "code, kbd, samp, pre";
|
|
1631
|
+
|
|
1632
|
+
.dx-tabular {
|
|
1633
|
+
font-family: var(--dx-font-family-figures), var(--bs-body-font-family);
|
|
1634
|
+
font-variant-numeric: tabular-nums;
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
:where(#{$dx-headings-1-4}).dx-tabular,
|
|
1638
|
+
:where(#{$dx-headings-1-4}) .dx-tabular {
|
|
1639
|
+
font-family: var(--dx-font-family-figures), var(--dx-font-family-display);
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
:where(#{$dx-monospace-elements}).dx-tabular,
|
|
1643
|
+
:where(#{$dx-monospace-elements}) .dx-tabular {
|
|
1644
|
+
font-family: var(--dx-font-family-figures), var(--bs-font-monospace);
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
// ----------------------------------------------------------------------------
|
|
1648
|
+
// DXField password fields: the eye as part of the input, actions that wrap
|
|
1649
|
+
// ----------------------------------------------------------------------------
|
|
1650
|
+
//
|
|
1651
|
+
// The reveal (eye) toggle is drawn as part of the field: the input's border
|
|
1652
|
+
// colour, radius and background, a muted icon, and the input's own focus
|
|
1653
|
+
// treatment (navy border + halo). As a plain `outline-secondary` button it was
|
|
1654
|
+
// a darker, square-cornered box stuck to a light rounded input. Driven through
|
|
1655
|
+
// Bootstrap's `--bs-btn-*` variables, so hover/active/focus keep Bootstrap's
|
|
1656
|
+
// resolution order. `.btn.` lifts it over `.btn-outline-secondary`.
|
|
1657
|
+
//
|
|
1658
|
+
// A `password-actions` slot (a Generate button) sits AFTER the input group,
|
|
1659
|
+
// not in it, with a gap: it is an ordinary button beside the field rather than
|
|
1660
|
+
// a third piece of the control. The group asks for room for
|
|
1661
|
+
// `--dx-password-input-min-width` of input plus the square eye; when the row
|
|
1662
|
+
// cannot give the group that AND the actions, the actions wrap onto their own
|
|
1663
|
+
// line below it, so the input never shrinks to a couple of characters. The
|
|
1664
|
+
// group still has `min-width: 0`: in a container narrower than the minimum it
|
|
1665
|
+
// shrinks rather than overflowing.
|
|
1666
|
+
$dx-password-input-min-width: 11rem !default;
|
|
1667
|
+
$dx-password-actions-gap: 0.5rem !default;
|
|
1668
|
+
|
|
1669
|
+
:root {
|
|
1670
|
+
--dx-password-input-min-width: #{$dx-password-input-min-width};
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
.btn.dx-password-reveal {
|
|
1674
|
+
--bs-btn-color: var(--bs-secondary-color);
|
|
1675
|
+
--bs-btn-bg: #{$input-bg};
|
|
1676
|
+
--bs-btn-border-color: var(--d-input-border-color);
|
|
1677
|
+
--bs-btn-border-radius: #{$input-border-radius};
|
|
1678
|
+
--bs-btn-hover-color: var(--bs-body-color);
|
|
1679
|
+
--bs-btn-hover-bg: var(--bs-tertiary-bg);
|
|
1680
|
+
--bs-btn-hover-border-color: var(--d-input-border-color);
|
|
1681
|
+
--bs-btn-active-color: var(--bs-body-color);
|
|
1682
|
+
--bs-btn-active-bg: var(--bs-tertiary-bg);
|
|
1683
|
+
--bs-btn-active-border-color: var(--d-input-border-color);
|
|
1684
|
+
--bs-btn-focus-box-shadow: #{$input-focus-box-shadow};
|
|
1685
|
+
|
|
1686
|
+
&:focus-visible {
|
|
1687
|
+
border-color: $input-focus-border-color;
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
// Disabled with its field: the disabled input's fill and border, not the
|
|
1692
|
+
// neutral outline-button look (`.btn:is(:disabled)` below), so the eye still
|
|
1693
|
+
// reads as part of the greyed-out control. `.input-group >` outranks that rule.
|
|
1694
|
+
.input-group > .btn.dx-password-reveal:is(:disabled, .disabled),
|
|
1695
|
+
fieldset:disabled .input-group > .btn.dx-password-reveal {
|
|
1696
|
+
--bs-btn-disabled-bg: #{$input-disabled-bg};
|
|
1697
|
+
--bs-btn-disabled-color: var(--bs-secondary-color);
|
|
1698
|
+
--bs-btn-disabled-border-color: var(--d-input-border-color);
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
.dx-password-field {
|
|
1702
|
+
display: flex;
|
|
1703
|
+
flex-wrap: wrap;
|
|
1704
|
+
align-items: flex-start;
|
|
1705
|
+
gap: $dx-password-actions-gap;
|
|
1706
|
+
|
|
1707
|
+
> .dx-password-field__group {
|
|
1708
|
+
// The eye is an icon-only square, `--dx-input-height` wide.
|
|
1709
|
+
flex: 1 1 calc(var(--dx-password-input-min-width) + var(--dx-input-height));
|
|
1710
|
+
min-width: 0;
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
.dx-password-field__actions {
|
|
1715
|
+
display: flex;
|
|
1716
|
+
flex-wrap: wrap;
|
|
1717
|
+
gap: $dx-password-actions-gap;
|
|
1718
|
+
min-width: 0;
|
|
1719
|
+
max-width: 100%;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1391
1722
|
// ----------------------------------------------------------------------------
|
|
1392
1723
|
// DXCurrencyInput — keep the amount usable in a narrow container
|
|
1393
1724
|
// ----------------------------------------------------------------------------
|
|
@@ -1396,10 +1727,14 @@ aside.dashboard-sidebar--light {
|
|
|
1396
1727
|
// ("10L Bag in Box") crushed the amount to ~32px. The amount keeps room for a
|
|
1397
1728
|
// price, the group still does not wrap (a wrapped affix would land on its own line
|
|
1398
1729
|
// with broken corners: the theme already makes every `.input-group` nowrap),
|
|
1399
|
-
// and the affix text wraps onto two lines instead.
|
|
1730
|
+
// and the affix text wraps onto two lines instead. The amount uses tabular
|
|
1731
|
+
// figures (#215), like every money value the library renders (the figures
|
|
1732
|
+
// face plus `tabular-nums`, as `.dx-tabular` above).
|
|
1400
1733
|
.dx-currency-input {
|
|
1401
1734
|
> .form-control {
|
|
1402
1735
|
min-width: 5.5rem;
|
|
1736
|
+
font-family: var(--dx-font-family-figures), var(--bs-body-font-family);
|
|
1737
|
+
font-variant-numeric: tabular-nums;
|
|
1403
1738
|
}
|
|
1404
1739
|
|
|
1405
1740
|
> .input-group-text {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"
|
|
2
|
+
|
|
3
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
4
|
+
|
|
5
|
+
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
-----------------------------------------------------------
|
|
9
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
10
|
+
-----------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
PREAMBLE
|
|
13
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
14
|
+
development of collaborative font projects, to support the font creation
|
|
15
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
16
|
+
open framework in which fonts may be shared and improved in partnership
|
|
17
|
+
with others.
|
|
18
|
+
|
|
19
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
20
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
21
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
22
|
+
redistributed and/or sold with any software provided that any reserved
|
|
23
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
24
|
+
however, cannot be released under any other type of license. The
|
|
25
|
+
requirement for fonts to remain under this license does not apply
|
|
26
|
+
to any document created using the fonts or their derivatives.
|
|
27
|
+
|
|
28
|
+
DEFINITIONS
|
|
29
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
30
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
31
|
+
include source files, build scripts and documentation.
|
|
32
|
+
|
|
33
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
34
|
+
copyright statement(s).
|
|
35
|
+
|
|
36
|
+
"Original Version" refers to the collection of Font Software components as
|
|
37
|
+
distributed by the Copyright Holder(s).
|
|
38
|
+
|
|
39
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
40
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
41
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
42
|
+
new environment.
|
|
43
|
+
|
|
44
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
45
|
+
writer or other person who contributed to the Font Software.
|
|
46
|
+
|
|
47
|
+
PERMISSION & CONDITIONS
|
|
48
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
49
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
50
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
51
|
+
Software, subject to the following conditions:
|
|
52
|
+
|
|
53
|
+
1) Neither the Font Software nor any of its individual components,
|
|
54
|
+
in Original or Modified Versions, may be sold by itself.
|
|
55
|
+
|
|
56
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
57
|
+
redistributed and/or sold with any software, provided that each copy
|
|
58
|
+
contains the above copyright notice and this license. These can be
|
|
59
|
+
included either as stand-alone text files, human-readable headers or
|
|
60
|
+
in the appropriate machine-readable metadata fields within text or
|
|
61
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
62
|
+
|
|
63
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
64
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
65
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
66
|
+
presented to the users.
|
|
67
|
+
|
|
68
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
69
|
+
Software shall not be used to promote, endorse or advertise any
|
|
70
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
71
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
72
|
+
permission.
|
|
73
|
+
|
|
74
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
75
|
+
must be distributed entirely under this license, and must not be
|
|
76
|
+
distributed under any other license. The requirement for fonts to
|
|
77
|
+
remain under this license does not apply to any document created
|
|
78
|
+
using the Font Software.
|
|
79
|
+
|
|
80
|
+
TERMINATION
|
|
81
|
+
This license becomes null and void if any of the above conditions are
|
|
82
|
+
not met.
|
|
83
|
+
|
|
84
|
+
DISCLAIMER
|
|
85
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
86
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
87
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
88
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
89
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
90
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
91
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
92
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
93
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
IBM Plex Sans, digits only, for the theme's "DX Figures" face (#215).
|
|
2
|
+
|
|
3
|
+
These are IBM's official Latin1 split woff2 files, copied unmodified from the
|
|
4
|
+
npm package @ibm/plex-sans 1.1.0 (fonts/split/woff2/), the upstream of
|
|
5
|
+
https://github.com/IBM/plex. The theme limits them to U+0030-0039 with
|
|
6
|
+
unicode-range; the files themselves are whole.
|
|
7
|
+
|
|
8
|
+
"Plex" is a Reserved Font Name under the SIL Open Font License (OFL.txt,
|
|
9
|
+
the package's LICENSE.txt, unmodified). A modified copy could not keep the
|
|
10
|
+
name, so these files must never be subset, re-encoded or otherwise changed.
|
|
11
|
+
To update them, replace them with newer upstream files and record the new
|
|
12
|
+
version and checksums here and in tests/bundle/theme-fonts.test.ts.
|
|
13
|
+
|
|
14
|
+
sha256:
|
|
15
|
+
b5ad7bd39f996144915f0ad9849a90183b27d8c28ad97ed98af5b1bebc51f6b1 IBMPlexSans-Regular-Latin1.woff2
|
|
16
|
+
b5610af04d0d4b5a14a621d96d974b993e945a065db1a8861918f69ef9321934 IBMPlexSans-Medium-Latin1.woff2
|
|
17
|
+
fff0ab3a88b0b4aa0b693e4f0201359a15183b08e3fa5696d1918d8f0ade8ad5 IBMPlexSans-SemiBold-Latin1.woff2
|
|
18
|
+
914f1400f363e636b6f9cc7965aa807ff01e93586e1437617525cba0a62aa78d IBMPlexSans-Bold-Latin1.woff2
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @component
|
|
3
|
+
* Type-safe wrapper around Bootstrap Vue Next BFormFile component.
|
|
4
|
+
* File picker with a browse button, file-name display and drag-and-drop
|
|
5
|
+
* zone. `v-model` is a `File` (single), `File[]` (`multiple`/`directory`)
|
|
6
|
+
* or `null`; setting it to `null` (or `[]`) also clears the native input.
|
|
7
|
+
* A disabled control (the prop, or a disabled fieldset) ignores dropped
|
|
8
|
+
* files. Slots: `label`, `placeholder`, `file-name` (`{ files, names }`)
|
|
9
|
+
* and `drop-placeholder`. Exposes BFormFile's `focus`, `blur` and `reset`.
|
|
10
|
+
*/
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
|
|
13
|
+
import { BFormFile } from "bootstrap-vue-next";
|
|
14
|
+
|
|
15
|
+
defineOptions({
|
|
16
|
+
inheritAttrs: false,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const bFormFileRef = ref<InstanceType<typeof BFormFile> | null>(null);
|
|
20
|
+
|
|
21
|
+
const rootElement = (): HTMLElement | null => {
|
|
22
|
+
const element = bFormFileRef.value?.$el as unknown;
|
|
23
|
+
return element instanceof HTMLElement ? element : null;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const nativeInput = (): HTMLInputElement | null =>
|
|
27
|
+
rootElement()?.querySelector<HTMLInputElement>('input[type="file"]') ?? null;
|
|
28
|
+
|
|
29
|
+
// bvn's drop handler checks only `noDrop`, so a disabled control still took
|
|
30
|
+
// a dropped file. The native input is :disabled both for the `disabled` prop
|
|
31
|
+
// and inside a disabled fieldset (which the attrs cannot see), so capture
|
|
32
|
+
// the drag events on BFormFile's root (useDropZone listens on the drop zone
|
|
33
|
+
// inside it) and stop them while the input is :disabled. dragleave too, or
|
|
34
|
+
// useDropZone's enter/leave counter drifts and the overlay sticks once the
|
|
35
|
+
// control is enabled again. Divergence from bvn: DIVERGENCES.md.
|
|
36
|
+
const blockedDragEvents = ["dragenter", "dragover", "dragleave", "drop"] as const;
|
|
37
|
+
let listeningRoot: HTMLElement | null = null;
|
|
38
|
+
|
|
39
|
+
const stopDragWhileDisabled = (event: Event) => {
|
|
40
|
+
if (nativeInput()?.matches(":disabled")) {
|
|
41
|
+
event.stopPropagation();
|
|
42
|
+
// Without this the browser opens a dropped file in the tab.
|
|
43
|
+
event.preventDefault();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
onMounted(() => {
|
|
48
|
+
listeningRoot = rootElement();
|
|
49
|
+
blockedDragEvents.forEach((type) =>
|
|
50
|
+
listeningRoot?.addEventListener(type, stopDragWhileDisabled, { capture: true })
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
onBeforeUnmount(() => {
|
|
55
|
+
blockedDragEvents.forEach((type) =>
|
|
56
|
+
listeningRoot?.removeEventListener(type, stopDragWhileDisabled, { capture: true })
|
|
57
|
+
);
|
|
58
|
+
listeningRoot = null;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// bvn clears its own file list when the model becomes null or [], but in the
|
|
62
|
+
// custom control it leaves the hidden native input holding the files (and
|
|
63
|
+
// `plain` keeps them on []), so a plain form submit (FormData) still posted
|
|
64
|
+
// them. Clear the native input directly: bvn's reset() would also set the
|
|
65
|
+
// model to null, echoing an extra update:modelValue to the parent.
|
|
66
|
+
// Read from BFormFile's own props: they are reactive and normalised
|
|
67
|
+
// (`modelValue` whether the parent wrote `v-model` or `:model-value`).
|
|
68
|
+
// Divergence from bvn: DIVERGENCES.md.
|
|
69
|
+
const isCleared = (value: unknown) =>
|
|
70
|
+
value === null || value === undefined || (Array.isArray(value) && value.length === 0);
|
|
71
|
+
|
|
72
|
+
watch(
|
|
73
|
+
() => bFormFileRef.value?.$props.modelValue,
|
|
74
|
+
(modelValue, previousModelValue) => {
|
|
75
|
+
if (isCleared(modelValue) && !isCleared(previousModelValue)) {
|
|
76
|
+
const input = nativeInput();
|
|
77
|
+
if (input) {
|
|
78
|
+
input.value = "";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
// A template ref on the wrapper would otherwise stop at the wrapper, so
|
|
85
|
+
// `reset()` (the only way to clear the native input's selection) is passed on.
|
|
86
|
+
defineExpose({
|
|
87
|
+
focus: () => bFormFileRef.value?.focus(),
|
|
88
|
+
blur: () => bFormFileRef.value?.blur(),
|
|
89
|
+
reset: () => bFormFileRef.value?.reset(),
|
|
90
|
+
get element() {
|
|
91
|
+
return bFormFileRef.value?.element ?? null;
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
<template>
|
|
97
|
+
<BFormFile ref="bFormFileRef" v-bind="$attrs">
|
|
98
|
+
<!-- Dynamically pass through all named slots with their props -->
|
|
99
|
+
<template v-for="(_, name) in $slots" :key="name" #[name]="slotProps">
|
|
100
|
+
<slot :name="name" v-bind="slotProps" />
|
|
101
|
+
</template>
|
|
102
|
+
</BFormFile>
|
|
103
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { BFormValidFeedback } from "bootstrap-vue-next";
|
|
3
|
+
|
|
4
|
+
defineOptions({
|
|
5
|
+
inheritAttrs: false,
|
|
6
|
+
});
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<BFormValidFeedback v-bind="$attrs">
|
|
11
|
+
<!-- Dynamically pass through all named slots -->
|
|
12
|
+
<template v-for="(_, name) in $slots" :key="name" #[name]="slotProps">
|
|
13
|
+
<slot :name="name" v-bind="slotProps" />
|
|
14
|
+
</template>
|
|
15
|
+
</BFormValidFeedback>
|
|
16
|
+
</template>
|