ArrayList
diff --git a/doc/changes.html b/doc/changes.html index c0b2947..6230523 100644 --- a/doc/changes.html +++ b/doc/changes.html @@ -22,12 +22,13 @@
Change log
-Version 2.0.0-beta.3
-Released: not yet (will be renamed to 2.0.0)
+Version 2.0.0-rc.1
+Released: not yet
New features
- Carousel plugin
- Gallery plugin +
- Resizable plugin
- CSS class
expanded
for initially expanded accordion items - Added styling for the
<mark>
element - ToggleSwitch can be applied to an
<input type="checkbox">
element, also automatically with thetoggle-switch
CSS class
@@ -39,6 +40,7 @@ - AJAX method
F.postForm
renamed toF.postFormJSON
as more AJAX methods were added - ToggleSwitch plugin method does not return a plugin instance anymore, but can convert multiple elements at once
- TreeView plugin renamed to Tree +
- Layout properties
F.left
andF.top
do not set the plain CSS property of the same name anymore but the actual position of the element relative to the document. They now only accept numbers as values. The difference is when an element is in a relative-positioned parent that is not at the origin (0/0) of the document.
Breaking changes
Breaking changes since v1
-
@@ -94,7 +96,7 @@
- Carousel (planned for 2.0 – done)
- ColorPicker on form field (planned for beta 2 – done)
- Gallery (planned for 2.0 – done) -
- Resizable (planned for 2.0) +
- Resizable (planned for 2.0 – done)
- TimePicker (planned for beta 2 – done)
Missing from v1
Breaking changes since v1
diff --git a/doc/color.html b/doc/color.html index 238ef8c..2c3a02c 100644 --- a/doc/color.html +++ b/doc/color.html @@ -24,7 +24,7 @@Color
diff --git a/doc/datacolor.html b/doc/datacolor.html
index c0cc8a8..a164dd7 100644
--- a/doc/datacolor.html
+++ b/doc/datacolor.html
@@ -98,7 +98,7 @@
diff --git a/doc/frontfire-core.html b/doc/frontfire-core.html
index 2009749..cb8a13f 100644
--- a/doc/frontfire-core.html
+++ b/doc/frontfire-core.html
@@ -24,7 +24,7 @@
@@ -1257,7 +1257,7 @@
- Gets the left location of the first selected Node in the document, or sets the left property of all selected Nodes, in pixels.
+ Gets the left location of the first selected Node, or sets the left location of all selected Nodes, relative to the document, in pixels.
If there are no Nodes selected, 0 is returned and setting the property does nothing.
Note that this is the rendered position that may be affected by CSS transforms.
- Gets the top location of the first selected Node in the document, or sets the top property of all selected Nodes, in pixels.
+ Gets the top location of the first selected Node, or sets the top location of all selected Nodes, relative to the document, in pixels.
If there are no Nodes selected, 0 is returned and setting the property does nothing.
Note that this is the rendered position that may be affected by CSS transforms.
An accordion contains multiple sections that can be expanded and collapsed separately.
diff --git a/doc/frontfire-ui-autostart.html b/doc/frontfire-ui-autostart.html
index 650b39c..5a2491a 100644
--- a/doc/frontfire-ui-autostart.html
+++ b/doc/frontfire-ui-autostart.html
@@ -24,7 +24,7 @@
Frontfire UI provides styles and extended behaviours for commonly used elements and applies some of them automatically.
diff --git a/doc/frontfire-ui-carousel.html b/doc/frontfire-ui-carousel.html
index ed4d4d7..03add81 100644
--- a/doc/frontfire-ui-carousel.html
+++ b/doc/frontfire-ui-carousel.html
@@ -24,7 +24,7 @@
Frontfire UI provides a layout of multiple items that are arranged horizontally and can be scrolled through by swipe gestures.
diff --git a/doc/frontfire-ui-classes.html b/doc/frontfire-ui-classes.html
index 5e1976a..3c90234 100644
--- a/doc/frontfire-ui-classes.html
+++ b/doc/frontfire-ui-classes.html
@@ -24,7 +24,7 @@
diff --git a/doc/frontfire-ui-colorpicker.html b/doc/frontfire-ui-colorpicker.html
index d3c7e8b..4385a4d 100644
--- a/doc/frontfire-ui-colorpicker.html
+++ b/doc/frontfire-ui-colorpicker.html
@@ -24,7 +24,7 @@
The default colour picker opens a platform-specific and much outdated colour selection dialog window.
diff --git a/doc/frontfire-ui-draggable.html b/doc/frontfire-ui-draggable.html
index 4ab21e0..2b8e6d6 100644
--- a/doc/frontfire-ui-draggable.html
+++ b/doc/frontfire-ui-draggable.html
@@ -66,7 +66,7 @@
Frontfire UI allows making any element draggable by mouse, touch or other pointer interaction.
diff --git a/doc/frontfire-ui-dropdown.html b/doc/frontfire-ui-dropdown.html
index 432d5cf..7accf32 100644
--- a/doc/frontfire-ui-dropdown.html
+++ b/doc/frontfire-ui-dropdown.html
@@ -24,7 +24,7 @@
Frontfire UI provides a dropdown panel that is placed near an originating element and overlays the page.
diff --git a/doc/frontfire-ui-form.html b/doc/frontfire-ui-form.html
index c053301..1a39960 100644
--- a/doc/frontfire-ui-form.html
+++ b/doc/frontfire-ui-form.html
@@ -24,7 +24,7 @@
Frontfire UI provides a responsive form layout system that is suitable for most data entry scenarios and can be customised for almost every special need.
diff --git a/doc/frontfire-ui-gallery.html b/doc/frontfire-ui-gallery.html
index 06795bd..ddbee22 100644
--- a/doc/frontfire-ui-gallery.html
+++ b/doc/frontfire-ui-gallery.html
@@ -24,7 +24,7 @@
A gallery presents images or photos in a row layout where all rows have a consistent width and the images are scaled automatically so that they fill up each row.
diff --git a/doc/frontfire-ui-image.html b/doc/frontfire-ui-image.html
index dd4f464..4e1f57e 100644
--- a/doc/frontfire-ui-image.html
+++ b/doc/frontfire-ui-image.html
@@ -24,7 +24,7 @@
Frontfire UI provides a set of image styles that can align and size images beautifully and provide decorations and overlay styles.
diff --git a/doc/frontfire-ui-installation.html b/doc/frontfire-ui-installation.html
index d85eb61..b1be42c 100644
--- a/doc/frontfire-ui-installation.html
+++ b/doc/frontfire-ui-installation.html
@@ -24,7 +24,7 @@
diff --git a/doc/frontfire-ui-menu.html b/doc/frontfire-ui-menu.html
index 34e0693..4a041f8 100644
--- a/doc/frontfire-ui-menu.html
+++ b/doc/frontfire-ui-menu.html
@@ -24,7 +24,7 @@
Frontfire UI provides a menu layout that can serve as website navigation or for web apps.
diff --git a/doc/frontfire-ui-message.html b/doc/frontfire-ui-message.html
index e3b3a3d..03cadad 100644
--- a/doc/frontfire-ui-message.html
+++ b/doc/frontfire-ui-message.html
@@ -24,7 +24,7 @@
Frontfire UI provides a set of message bar styles that can be used to inform the user about success or error messages at different levels.
diff --git a/doc/frontfire-ui-modal.html b/doc/frontfire-ui-modal.html
index 1c599a4..b234ec3 100644
--- a/doc/frontfire-ui-modal.html
+++ b/doc/frontfire-ui-modal.html
@@ -24,7 +24,7 @@
Frontfire UI provides a modal panel that overlays the page and can be used to display important messages that must be confirmed before proceding with anything else on the page, or to display details about something on-demand without using page layout space.
diff --git a/doc/frontfire-ui-notification.html b/doc/frontfire-ui-notification.html
index 68509a1..174cdeb 100644
--- a/doc/frontfire-ui-notification.html
+++ b/doc/frontfire-ui-notification.html
@@ -24,7 +24,7 @@
Frontfire UI provides a notification that overlays the page and disappears after a short while.
diff --git a/doc/frontfire-ui-offcanvas.html b/doc/frontfire-ui-offcanvas.html
index c62a53e..2a9b261 100644
--- a/doc/frontfire-ui-offcanvas.html
+++ b/doc/frontfire-ui-offcanvas.html
@@ -31,7 +31,7 @@
An off-canvas element appears on request on either side of the page and overlays or pushes away the main page content.
diff --git a/doc/frontfire-ui-options.html b/doc/frontfire-ui-options.html
index c5c306b..6d261d2 100644
--- a/doc/frontfire-ui-options.html
+++ b/doc/frontfire-ui-options.html
@@ -24,7 +24,7 @@
diff --git a/doc/frontfire-ui-page.html b/doc/frontfire-ui-page.html
index 245f426..d8fbba5 100644
--- a/doc/frontfire-ui-page.html
+++ b/doc/frontfire-ui-page.html
@@ -24,7 +24,7 @@
Frontfire UI provides a set of basic page layout styles that support many web design scenarios with ease.
diff --git a/doc/frontfire-ui-progressbar.html b/doc/frontfire-ui-progressbar.html
index 32d154f..ca41176 100644
--- a/doc/frontfire-ui-progressbar.html
+++ b/doc/frontfire-ui-progressbar.html
@@ -24,7 +24,7 @@
Frontfire UI provides a progress bars component that shows the progression of a task or other visualised values between a minimum and a maximum.
diff --git a/doc/frontfire-ui-resizable.html b/doc/frontfire-ui-resizable.html
new file mode 100644
index 0000000..9aef0a2
--- /dev/null
+++ b/doc/frontfire-ui-resizable.html
@@ -0,0 +1,395 @@
+
+
+
+ Frontfire UI allows resizing any element by draggable handles at each side.
+
+ This plugin is available in the Minimal and Complete bundles.
+
+ This plugin depends on the plugins: draggable
+
+ Resizable elements allow the user to change the width or height of an element.
+ Call the
+ The examples on this page use additional CSS styles that are not shown in the source boxes.
+ Read the source code of this page or use the browser’s DOM inspector to see these styles.
+
+ The box handle colours can be customised with the CSS variables that start with “--resizable-”.
+
+ Here are examples that demonstrate the basic usage of the resizable feature.
+ These static-positioned elements will be changed to relative position to maintain their new position but still take their space in the layout flow.
+ You can also start with absolute-positioned elements which won’t be changed then.
+ Touch actions to scroll the page are disabled in the direction the elements may be dragged.
+
+
+
+ The minimum and maximum size can be restricted while resizing the element.
+
+ The dimensions of a resizable element can be restricted to another element or the parent element with the
+ This example shows how the resizable events can be used to react to resizing events or restrict the operations.
+ The events and their data properties are described below.
+
+ The following options are available:
+
+ This plugin provides methods to control the resizable.
+
+ Removes the resizing features from the elements.
+
+ This plugin triggers events for the resizable elements.
+
+ Triggered when the resize operation has ended.
+ The following properties are provided with the event:
+
+ Triggered when the element is being resized.
+ This event can be cancelled by calling
+ Triggered when the element is starting to be resized.
+ This event can be cancelled by calling
Frontfire UI allows making the children of any element selectable.
diff --git a/doc/frontfire-ui-slider.html b/doc/frontfire-ui-slider.html
index 87c77fe..281f0a8 100644
--- a/doc/frontfire-ui-slider.html
+++ b/doc/frontfire-ui-slider.html
@@ -24,7 +24,7 @@
Frontfire UI provides a value selection control that shows the selected value on a bar and allows dragging it to change the value.
diff --git a/doc/frontfire-ui-sortable.html b/doc/frontfire-ui-sortable.html
index 9e4a1b5..2c36110 100644
--- a/doc/frontfire-ui-sortable.html
+++ b/doc/frontfire-ui-sortable.html
@@ -103,7 +103,7 @@
Frontfire UI allows sorting elements within their parent by mouse, touch or other pointer interaction.
diff --git a/doc/frontfire-ui-table.html b/doc/frontfire-ui-table.html
index 7c8445e..bab6b8e 100644
--- a/doc/frontfire-ui-table.html
+++ b/doc/frontfire-ui-table.html
@@ -24,7 +24,7 @@
Tables allow the presentation of tabular data.
diff --git a/doc/frontfire-ui-tabs.html b/doc/frontfire-ui-tabs.html
index 4c17ee9..d0b3b54 100644
--- a/doc/frontfire-ui-tabs.html
+++ b/doc/frontfire-ui-tabs.html
@@ -24,7 +24,7 @@
Frontfire UI provides a layout for pages with separate content that can be switched through tab headers.
diff --git a/doc/frontfire-ui-timepicker.html b/doc/frontfire-ui-timepicker.html
index 86e445b..48c2a8b 100644
--- a/doc/frontfire-ui-timepicker.html
+++ b/doc/frontfire-ui-timepicker.html
@@ -24,7 +24,7 @@
HTML defines a number of input control elements for date- and time-related input.
diff --git a/doc/frontfire-ui-toggleswitch.html b/doc/frontfire-ui-toggleswitch.html
index 761fe75..2a8a966 100644
--- a/doc/frontfire-ui-toggleswitch.html
+++ b/doc/frontfire-ui-toggleswitch.html
@@ -24,7 +24,7 @@
Frontfire UI provides a toggle switch that has the same function as a checkbox but the appearance of a slider button.
diff --git a/doc/frontfire-ui-tree.html b/doc/frontfire-ui-tree.html
index ee75ace..9424bc8 100644
--- a/doc/frontfire-ui-tree.html
+++ b/doc/frontfire-ui-tree.html
@@ -24,7 +24,7 @@
Frontfire UI provides a hierarchical tree selection control.
diff --git a/doc/frontfire-ui-typography.html b/doc/frontfire-ui-typography.html
index 00dadaf..8761b77 100644
--- a/doc/frontfire-ui-typography.html
+++ b/doc/frontfire-ui-typography.html
@@ -24,7 +24,7 @@
Frontfire UI provides a rich set of elementary typography styles.
diff --git a/doc/frontfire-ui-variables.html b/doc/frontfire-ui-variables.html
index ed43161..bf52de1 100644
--- a/doc/frontfire-ui-variables.html
+++ b/doc/frontfire-ui-variables.html
@@ -24,7 +24,7 @@
@@ -3087,6 +3087,39 @@
+ Type: color
+ Default: see description
+ (for Resizable)
+
+ The fill colour of a box handle of a resizable element.
+ The default value is:
+ See also: --resizable-handle-box-border
+
+ Type: color
+ Default: silver
+ Dark default: gray
+ (for Resizable)
+
+ The colour of the border around a box handle of a resizable element.
+
+ See also: --resizable-handle-box-background
+
diff --git a/doc/frontfire-ui-wheelscrolling.html b/doc/frontfire-ui-wheelscrolling.html
index 42de13a..95da40a 100644
--- a/doc/frontfire-ui-wheelscrolling.html
+++ b/doc/frontfire-ui-wheelscrolling.html
@@ -24,7 +24,7 @@
This plugin enables custom mouse wheel scrolling on elements.
diff --git a/doc/index.html b/doc/index.html
index 7d87a02..4fe3e2b 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -19,7 +19,7 @@
The Frontfire Web Frontend Toolkit offers essential styles and effects combined with a consistent set of interactive widgets and layout utilities.
@@ -202,6 +202,12 @@ DataColor
Frontfire Core
left
left
→ Numbertop
top
→ NumberAccordion plugin
Autostart
Carousel plugin
Frontfire UI CSS classes
ColorPicker plugin
Draggable plugin
Dropdown plugin
Form module
Gallery plugin
Image module
Installation
Menu plugin
Message plugin
Modal plugin
Notification plugin
OffCanvas plugin
Plugin options
Page module
Progressbar plugin
Resizable plugin
+ Description
+ resizable()
plugin method on any element to add the resizable feature.
+ The element size can be constrained by providing options to that method or handling events.
+ This feature provides a low-level behaviour to elements that usually is not used on its own but rather by other Frontfire UI features to build upon it.
+ Basic examples
+ Minimum and maximum size
+ Resizable within a container
+ containment
option.
+ Snapping to grid within the container
+ Resize event handler
+
+
+ Options
+
+
+
+
+
+
+
+
+
+ Name
+ Type
+ Description
+ Default
+
+
+
+ containment
String, Node(s)
+ Constrains the resizing inside the specified element, specified as CSS selector or Node (collection), or the “parent” of the resized element or the “viewport”.
+ None
+
+
+
+ grid
Number array
+ The grid to snap the resized element to during resizing, as
+ [x, y]
in pixels. The grid is aligned at the top left corner of the parent element.None
+
+
+
+ handles
String
+ The resizing handles to use, comma-separated. Can be “all” or a combination of “n, ne, e, se, s, sw, w, nw” for the cardinal directions.
+ All directions
+
+
+
+ handleClass
String
+ Additional CSS class for the handle elements. Known class: “box”.
+ None
+
+
+
+ handleWidth
Number
+ The width of the default handles, in pixels.
+ 10
+
+
+
+ maxHeight
Number
+ The maximum height to keep during resizing, in pixels.
+ None
+
+
+
+ maxWidth
Number
+ The maximum width to keep during resizing, in pixels.
+ None
+
+
+
+ minHeight
Number
+ The minimum height to keep during resizing, in pixels.
+ None
+
+
+
+ minWidth
Number
+ The minimum width to keep during resizing, in pixels.
+ None
+
+
+
+
+ scroll
Boolean
+ Indicates whether the window should scroll to keep the resized edge visible.
+ false
+ Plugin methods
+ remove
+
+
+ remove()
→ FrontfirePlugin events
+ resizableend
+
+
+ edge
: The name of the resized edge: “top”, “bottom”, “left”, “right”negative
: true
if the resized edge is left/upwards; false
if the edge is right/downwards.vertical
: true
if the resize direction is vertical; false
if the direction is horizontal.resizing
+ event.preventDefault()
to prevent the current size change, but if the element has already been resized, it is usually better to set the event’s newPosition
and newLength
properties to a desired value.
+ The following properties are provided with the event:
+
+
+ edge
: The name of the resized edge: “top”, “bottom”, “left”, “right”negative
: true
if the resized edge is left/upwards; false
if the edge is right/downwards.newLength
: The length of the element along the resize axis after applying the size, in pixels. This property can be set to any other length that the element should be sized to instead.newPosition
: The position of the element along the resize axis after applying the size, in pixels. This property can be set to any other position that the element should be moved to instead.vertical
: true
if the resize direction is vertical; false
if the direction is horizontal.resizablestart
+ event.preventDefault()
to prevent the resizing.
+ The following properties are provided with the event:
+
+
+ edge
: The name of the resized edge: “top”, “bottom”, “left”, “right”negative
: true
if the resized edge is left/upwards; false
if the edge is right/downwards.vertical
: true
if the resize direction is vertical; false
if the direction is horizontal.Selectable plugin
Slider plugin
Sortable plugin
Table module
Tabs plugin
TimePicker plugin
ToggleSwitch plugin
Tree plugin
Typography module
Frontfire UI CSS variables
--progress-warning-label-color
--resizable-handle-box-background
+
+ var(--default-background)
+ --resizable-handle-box-border
+ --selectable-focused-border
WheelScrolling plugin
Frontfire Web Frontend Toolkit
Frontfire UI
Progress bar with value display
+
+ Resizable
+ Plugin demo
+
+ Making elements resizable
+
Selectable
Plugin demo
diff --git a/readme.md b/readme.md
index d4b58ce..21efecd 100644
--- a/readme.md
+++ b/readme.md
@@ -41,10 +41,10 @@ The following is the content of the release archive. All files in readable and m
|-----------------------|----------------|-------------|
| ArrayList | arraylist.js
arraylist.min.js (3.1 KiB) | – |
| Frontfire Core | frontfire-core.js
frontfire-core.min.js (10 KiB) | frontfire-core-singlefile.js
frontfire-core-singlefile.min.js (13 KiB) |
-| Frontfire UI
Minimal | frontfire-ui-minimal.js
frontfire-ui-minimal.min.js (16 KiB) | frontfire-ui-minimal-singlefile.js
frontfire-ui-minimal-singlefile.min.js (28 KiB) |
+| Frontfire UI
Minimal | frontfire-ui-minimal.js
frontfire-ui-minimal.min.js (17 KiB) | frontfire-ui-minimal-singlefile.js
frontfire-ui-minimal-singlefile.min.js (29 KiB) |
| Color | color.js
color.min.js (2.6 KiB) | – |
| DataColor | datacolor.js
datacolor.min.js (1.2 KiB) | – |
-| Frontfire UI
Complete | frontfire-ui-complete.js
frontfire-ui-complete.min.js (39 KiB) | frontfire-ui-complete-singlefile.js
frontfire-ui-complete-singlefile.min.js (54 KiB) |
+| Frontfire UI
Complete | frontfire-ui-complete.js
frontfire-ui-complete.min.js (40 KiB) | frontfire-ui-complete-singlefile.js
frontfire-ui-complete-singlefile.min.js (55 KiB) |
### CSS files
@@ -126,7 +126,7 @@ Features
| Modal | A modal panel that overlays the page | | ✔️ | ✔️ |
| Notification | Short pop-up notifications | | ✔️ | ✔️ |
| OffCanvas | A panel that opens from the side of the page | | ✔️ | ✔️ |
-| Resizable | Supports primitive resize interactions on elements | | 🚧 | 🚧 |
+| Resizable | Supports primitive resize interactions on elements | | ✔️ | ✔️ |
| Selectable | Enhanced list boxes and dropdown select boxes | | ✔️ | ✔️ |
| Sortable | Supports primitive reorder interactions on the children of an element | | ✔️ | ✔️ |
| Table | Designs last visible table column/row | | ✔️ | ✔️ |
diff --git a/src/css/frontfire-ui-complete.scss b/src/css/frontfire-ui-complete.scss
index 3f03315..b65ae0c 100644
--- a/src/css/frontfire-ui-complete.scss
+++ b/src/css/frontfire-ui-complete.scss
@@ -1,4 +1,4 @@
-/*! frontfire-ui-complete.scss v2.0.0-beta.3 | @license MIT | ygoe.de */
+/*! frontfire-ui-complete.scss v2.0.0-rc.1 | @license MIT | ygoe.de */
/* build-dir(build) */
// Copyright (c) 2022-2023, Yves Goergen, https://ygoe.de
@@ -33,13 +33,15 @@
@import "plugins/typography";
@import "plugins/table";
@import "plugins/image";
-@import "plugins/message";
-@import "plugins/notification";
@import "plugins/form";
-@import "plugins/offcanvas";
-@import "plugins/modal";
+
@import "plugins/dropdown";
@import "plugins/menu";
+@import "plugins/message";
+@import "plugins/modal";
+@import "plugins/notification";
+@import "plugins/offcanvas";
+@import "plugins/resizable";
@import "plugins/selectable";
// Import all modules of the complete profile
diff --git a/src/css/frontfire-ui-minimal.scss b/src/css/frontfire-ui-minimal.scss
index 4d03d67..51ca77e 100644
--- a/src/css/frontfire-ui-minimal.scss
+++ b/src/css/frontfire-ui-minimal.scss
@@ -1,4 +1,4 @@
-/*! frontfire-ui-minimal.scss v2.0.0-beta.3 | @license MIT | ygoe.de */
+/*! frontfire-ui-minimal.scss v2.0.0-rc.1 | @license MIT | ygoe.de */
/* build-dir(build) */
// Copyright (c) 2022-2023, Yves Goergen, https://ygoe.de
@@ -33,11 +33,13 @@
@import "plugins/typography";
@import "plugins/table";
@import "plugins/image";
-@import "plugins/message";
-@import "plugins/notification";
@import "plugins/form";
-@import "plugins/offcanvas";
-@import "plugins/modal";
+
@import "plugins/dropdown";
@import "plugins/menu";
+@import "plugins/message";
+@import "plugins/modal";
+@import "plugins/notification";
+@import "plugins/offcanvas";
+@import "plugins/resizable";
@import "plugins/selectable";
diff --git a/src/css/plugins/resizable.scss b/src/css/plugins/resizable.scss
new file mode 100644
index 0000000..9722931
--- /dev/null
+++ b/src/css/plugins/resizable.scss
@@ -0,0 +1,36 @@
+.ff-resizable-handle
+{
+ user-select: none;
+ &.box
+ {
+ border: 1px solid var(--resizable-handle-box-border);
+ background-color: var(--resizable-handle-box-background, var(--default-background));
+ width: 7px;
+ height: 7px;
+ z-index: 900;
+ position: relative;
+ transition: background-color var(--animation-duration) var(--animation-function), border-color var(--animation-duration) var(--animation-function);
+ &::after
+ {
+ display: block;
+ content: '';
+ position: absolute;
+ top: -5px;
+ right: -5px;
+ bottom: -5px;
+ left: -5px;
+ }
+ &:hover::after
+ {
+ background: rgba(0, 0, 0, 0.05);
+ .dark &
+ {
+ background: rgba(255, 255, 255, 0.15);
+ }
+ }
+ }
+}
+.hide-handles .ff-resizable-handle.box
+{
+ display: none;
+}
diff --git a/src/css/variables.scss b/src/css/variables.scss
index 76552c1..d348659 100644
--- a/src/css/variables.scss
+++ b/src/css/variables.scss
@@ -326,6 +326,11 @@ $viewportWidthDesktop: 1200px;
--progress-success-color: #6ec418;
+ // ========== Resizable ==========
+
+ --resizable-handle-box-border: silver;
+
+
// ========== Slider ==========
// Width of the track bar
@@ -517,6 +522,11 @@ $viewportWidthDesktop: 1200px;
--submenu-color: var(--default-text-color);
+ // ========== Resizable ==========
+
+ --resizable-handle-box-border: gray;
+
+
// ========== Slider ==========
--slider-background: #505050;
diff --git a/src/js/arraylist.js b/src/js/arraylist.js
index fe74425..b5e66f3 100644
--- a/src/js/arraylist.js
+++ b/src/js/arraylist.js
@@ -1,4 +1,4 @@
-/*! arraylist.js v2.0.0-beta.3 | @license MIT | ygoe.de */
+/*! arraylist.js v2.0.0-rc.1 | @license MIT | ygoe.de */
/* build-dir(build) */
// Copyright (c) 2021-2023, Yves Goergen, https://ygoe.de
@@ -87,7 +87,7 @@
const Array_prototype = Array.prototype;
// Version identification
- ArrayList.version = "2.0.0-beta.3";
+ ArrayList.version = "2.0.0-rc.1";
// ==================== Array extensions and general methods ====================
diff --git a/src/js/color.js b/src/js/color.js
index 205af26..131763c 100644
--- a/src/js/color.js
+++ b/src/js/color.js
@@ -1,4 +1,4 @@
-/*! color.js v2.0.0-beta.3 | @license MIT | ygoe.de */
+/*! color.js v2.0.0-rc.1 | @license MIT | ygoe.de */
/* build-dir(build) */
// Encoding: UTF-8 without BOM (auto-detect: °°°°°) for built-in color names
diff --git a/src/js/datacolor.js b/src/js/datacolor.js
index 9ef90d1..5597855 100644
--- a/src/js/datacolor.js
+++ b/src/js/datacolor.js
@@ -1,4 +1,4 @@
-/*! datacolor.js v2.0.0-beta.3 | @license MIT | ygoe.de */
+/*! datacolor.js v2.0.0-rc.1 | @license MIT | ygoe.de */
/* build-dir(build) */
// Encoding: UTF-8 without BOM (auto-detect: °°°°°) for built-in color names
diff --git a/src/js/frontfire-core-singlefile.js b/src/js/frontfire-core-singlefile.js
index 50c93ce..1721959 100644
--- a/src/js/frontfire-core-singlefile.js
+++ b/src/js/frontfire-core-singlefile.js
@@ -1,4 +1,4 @@
-/*! frontfire-core-singlefile.js v2.0.0-beta.3 | @license MIT | ygoe.de */
+/*! frontfire-core-singlefile.js v2.0.0-rc.1 | @license MIT | ygoe.de */
/* no-iife */
/* build-dir(build) */
/* no-bundle-suffix */
diff --git a/src/js/frontfire-core.js b/src/js/frontfire-core.js
index e1dddd2..e9bb783 100644
--- a/src/js/frontfire-core.js
+++ b/src/js/frontfire-core.js
@@ -1,4 +1,4 @@
-/*! frontfire-core.js v2.0.0-beta.3 | @license MIT | ygoe.de */
+/*! frontfire-core.js v2.0.0-rc.1 | @license MIT | ygoe.de */
/* build-dir(build) */
// Copyright (c) 2021-2023, Yves Goergen, https://ygoe.de
@@ -1211,8 +1211,8 @@
parseFloat(computedStyle.borderLeftWidth) + parseFloat(computedStyle.borderRightWidth);
}
- // Gets the top location of the first selected Node in the document, or sets the top property of
- // all selected Nodes, in pixels.
+ // Gets the top location of the first selected Node, or sets the top location of all selected
+ // Nodes, relative to the document, in pixels.
// Note that this is the rendered position that may be affected by CSS transforms.
// See also: jQuery.offset()
object_defineProperty(Frontfire_prototype, "top", {
@@ -1222,14 +1222,17 @@
return this.array[0].getBoundingClientRect().top + window.scrollY;
},
set: function (value) {
- if (isNumber(value))
- value += "px";
- this.forEach(n => n.style.top = value);
+ this.forEach(n => {
+ let realPos = n.getBoundingClientRect().top + window.scrollY;
+ let computedPos = parseFloat(n.F.computedStyle.top);
+ value -= realPos - computedPos;
+ n.style.top = value + "px";
+ });
}
});
- // Gets the left location of the first selected Node in the document, or sets the left property
- // of all selected Nodes, in pixels.
+ // Gets the left location of the first selected Node, or sets the left location of all selected
+ // Nodes, relative to the document, in pixels.
// Note that this is the rendered position that may be affected by CSS transforms.
// See also: jQuery.offset()
object_defineProperty(Frontfire_prototype, "left", {
@@ -1239,9 +1242,12 @@
return this.array[0].getBoundingClientRect().left + window.scrollX;
},
set: function (value) {
- if (isNumber(value))
- value += "px";
- this.forEach(n => n.style.left = value);
+ this.forEach(n => {
+ let realPos = n.getBoundingClientRect().left + window.scrollX;
+ let computedPos = parseFloat(n.F.computedStyle.left);
+ value -= realPos - computedPos;
+ n.style.left = value + "px";
+ });
}
});
diff --git a/src/js/frontfire-ui-complete-singlefile.js b/src/js/frontfire-ui-complete-singlefile.js
index 6a646d1..8caa21d 100644
--- a/src/js/frontfire-ui-complete-singlefile.js
+++ b/src/js/frontfire-ui-complete-singlefile.js
@@ -1,4 +1,4 @@
-/*! frontfire-ui-complete-singlefile.js v2.0.0-beta.3 | @license MIT | ygoe.de */
+/*! frontfire-ui-complete-singlefile.js v2.0.0-rc.1 | @license MIT | ygoe.de */
/* no-iife */
/* build-dir(build) */
/* no-bundle-suffix */
diff --git a/src/js/frontfire-ui-complete.js b/src/js/frontfire-ui-complete.js
index 1f092fc..faeb53c 100644
--- a/src/js/frontfire-ui-complete.js
+++ b/src/js/frontfire-ui-complete.js
@@ -1,4 +1,4 @@
-/*! frontfire-ui-complete.js v2.0.0-beta.3 | @license MIT | ygoe.de */
+/*! frontfire-ui-complete.js v2.0.0-rc.1 | @license MIT | ygoe.de */
/* iife-params(F, window, document) */
/* iife-args(Frontfire, window, document) */
/* build-dir(build) */
@@ -37,6 +37,7 @@ import "./plugins/modal";
import "./plugins/notification";
import "./plugins/offcanvas";
import "./plugins/page";
+import "./plugins/resizable";
import "./plugins/selectable";
import "./plugins/sortable";
import "./plugins/table";
@@ -54,7 +55,4 @@ import "./plugins/toggleswitch";
import "./plugins/tree";
import "./plugins/wheelscrolling";
-// TODO: Convert and add the following groups of Frontfire 1 modules, with accompanying CSS:
-//import "./plugins/resizable";
-
F.runAutostart();
diff --git a/src/js/frontfire-ui-minimal-singlefile.js b/src/js/frontfire-ui-minimal-singlefile.js
index c045b05..9e1e315 100644
--- a/src/js/frontfire-ui-minimal-singlefile.js
+++ b/src/js/frontfire-ui-minimal-singlefile.js
@@ -1,4 +1,4 @@
-/*! frontfire-ui-minimal-singlefile.js v2.0.0-beta.3 | @license MIT | ygoe.de */
+/*! frontfire-ui-minimal-singlefile.js v2.0.0-rc.1 | @license MIT | ygoe.de */
/* no-iife */
/* build-dir(build) */
/* no-bundle-suffix */
diff --git a/src/js/frontfire-ui-minimal.js b/src/js/frontfire-ui-minimal.js
index 8a0e8bb..00a7893 100644
--- a/src/js/frontfire-ui-minimal.js
+++ b/src/js/frontfire-ui-minimal.js
@@ -1,4 +1,4 @@
-/*! frontfire-ui-minimal.js v2.0.0-beta.3 | @license MIT | ygoe.de */
+/*! frontfire-ui-minimal.js v2.0.0-rc.1 | @license MIT | ygoe.de */
/* iife-params(F, window, document) */
/* iife-args(Frontfire, window, document) */
/* build-dir(build) */
@@ -37,6 +37,7 @@ import "./plugins/modal";
import "./plugins/notification";
import "./plugins/offcanvas";
import "./plugins/page";
+import "./plugins/resizable";
import "./plugins/selectable";
import "./plugins/sortable";
import "./plugins/table";
diff --git a/src/js/plugins/dropdown.js b/src/js/plugins/dropdown.js
index d52ab5f..ef6b3cc 100644
--- a/src/js/plugins/dropdown.js
+++ b/src/js/plugins/dropdown.js
@@ -256,13 +256,6 @@ function createDropdown(target, options) {
// Always set the dropdown container width to consider minWidth or extra width for a scrollbar
container.F.borderWidth = dropdownWidth;
- // Compensate for offset element (possibly due to child element margins) if the closest
- // "position: relative" parent is not
- if (container.offsetParent?.F.computedStyle.position === "relative") {
- top -= container.offsetParent.F.top;
- left -= container.offsetParent.F.left;
- }
-
container.F.top = top;
container.F.left = left;
// TODO: Use Animation instead of forceReflow()
diff --git a/src/js/plugins/resizable.js b/src/js/plugins/resizable.js
new file mode 100644
index 0000000..9182a45
--- /dev/null
+++ b/src/js/plugins/resizable.js
@@ -0,0 +1,282 @@
+// ==================== Resizable plugin ====================
+
+const resizableClass = "ff-resizable";
+
+// Defines default options for the resizable plugin.
+let resizableDefaults = {
+ // The aspect ratio (x/y) to maintain during resizing, or true to maintain the initial aspect ratio.
+ // TODO: Uncomment documentation when implemented
+ aspectRatio: undefined,
+
+ // The resizing handles to use. Can be "all" or a combination of "n,ne,e,se,s,sw,w,nw". Default: All.
+ handles: undefined,
+
+ // The width of the default handles, in pixels.
+ handleWidth: 10,
+
+ // Additional CSS class for the handle elements. Known class: "box".
+ handleClass: undefined,
+
+ // Constrains the resizing inside the specified element or the "parent" of the resized element or the "viewport".
+ containment: undefined,
+
+ // The grid to snap the resized element to during resizing, as [x, y] in pixels.
+ grid: undefined,
+
+ // The minimum width to keep during resizing, in pixels.
+ minWidth: undefined,
+
+ // The minimum height to keep during resizing, in pixels.
+ minHeight: undefined,
+
+ // The maximum width to keep during resizing, in pixels.
+ maxWidth: undefined,
+
+ // The maximum height to keep during resizing, in pixels.
+ maxHeight: undefined,
+
+ // Indicates whether the window should scroll to keep the resized edge visible.
+ scroll: false
+};
+
+// Makes each selected element resizable.
+function resizable(options) {
+ return this.forEach(elem => {
+ if (elem.classList.contains(resizableClass)) return; // Already done
+ elem.classList.add(resizableClass);
+ let handleElements = F();
+ let opt = F.initOptions("resizable", elem, {}, options);
+
+ let aspectRatio = opt.aspectRatio;
+ if (aspectRatio === true || aspectRatio === "true")
+ aspectRatio = elem.F.borderWidth / elem.F.borderHeight;
+ if (F.isNumber(aspectRatio))
+ aspectRatio = parseFloat(aspectRatio);
+ if (aspectRatio === 0 || !isFinite(aspectRatio) || !F.isNumber(aspectRatio))
+ aspectRatio = undefined;
+
+ if (elem.F.computedStyle.position === "static") {
+ opt._wasPositionStatic = true;
+ elem.style.position = "relative";
+ }
+
+ let optHandles = opt.handles;
+ if (optHandles === undefined)
+ optHandles = "all";
+ if (optHandles === "all")
+ optHandles = "n,ne,e,se,s,sw,w,nw";
+ if (F.isString(optHandles))
+ optHandles = optHandles.replace(/\s/g, "").toLowerCase().split(",");
+
+ let vCursor = "ns-resize";
+ let hCursor = "ew-resize";
+ let nwCursor = "nwse-resize";
+ let neCursor = "nesw-resize";
+
+ if (opt.handleClass === "box") {
+ if (optHandles.indexOf("n") !== -1)
+ addHandle({ left: "calc(50% - 4px)", top: "-9px" }, vCursor, true, true); // Top edge
+ if (optHandles.indexOf("e") !== -1)
+ addHandle({ right: "-9px", top: "calc(50% - 4px)" }, hCursor, false, false); // Right edge
+ if (optHandles.indexOf("s") !== -1)
+ addHandle({ left: "calc(50% - 4px)", bottom: "-9px" }, vCursor, true, false); // Bottom edge
+ if (optHandles.indexOf("w") !== -1)
+ addHandle({ left: "-9px", top: "calc(50% - 4px)" }, hCursor, false, true); // Left edge
+
+ if (optHandles.indexOf("ne") !== -1)
+ addHandle({ top: "-9px", right: "-9px" }, neCursor, false, false, true, true); // Top right corner
+ if (optHandles.indexOf("se") !== -1)
+ addHandle({ bottom: "-9px", right: "-9px" }, nwCursor, false, false, true, false); // Bottom right corner
+ if (optHandles.indexOf("sw") !== -1)
+ addHandle({ bottom: "-9px", left: "-9px" }, neCursor, false, true, true, false); // Bottom left corner
+ if (optHandles.indexOf("nw") !== -1)
+ addHandle({ top: "-9px", left: "-9px" }, nwCursor, false, true, true, true); // Top left corner
+ }
+ else {
+ let w = opt.handleWidth;
+ if (optHandles.indexOf("n") !== -1)
+ addHandle({ left: w / 2 + "px", right: w / 2 + "px", top: -w / 2 + "px", height: w + "px" }, vCursor, true, true); // Top edge
+ if (optHandles.indexOf("e") !== -1)
+ addHandle({ top: w / 2 + "px", bottom: w / 2 + "px", right: -w / 2 + "px", width: w + "px" }, hCursor, false, false); // Right edge
+ if (optHandles.indexOf("s") !== -1)
+ addHandle({ left: w / 2 + "px", right: w / 2 + "px", bottom: -w / 2 + "px", height: w + "px" }, vCursor, true, false); // Bottom edge
+ if (optHandles.indexOf("w") !== -1)
+ addHandle({ top: w / 2 + "px", bottom: w / 2 + "px", left: -w / 2 + "px", width: w + "px" }, hCursor, false, true); // Left edge
+
+ if (optHandles.indexOf("ne") !== -1)
+ addHandle({ right: -w / 2 + "px", top: -w / 2 + "px", width: w + "px", height: w + "px" }, neCursor, false, false, true, true); // Top right corner
+ if (optHandles.indexOf("se") !== -1)
+ addHandle({ right: -w / 2 + "px", bottom: -w / 2 + "px", width: w + "px", height: w + "px" }, nwCursor, false, false, true, false); // Bottom right corner
+ if (optHandles.indexOf("sw") !== -1)
+ addHandle({ left: -w / 2 + "px", bottom: -w / 2 + "px", width: w + "px", height: w + "px" }, neCursor, false, true, true, false); // Bottom left corner
+ if (optHandles.indexOf("nw") !== -1)
+ addHandle({ left: -w / 2 + "px", top: -w / 2 + "px", width: w + "px", height: w + "px" }, nwCursor, false, true, true, true); // Top left corner
+ }
+
+ opt._disabledObserver = elem.F.observeDisabled(disabled => updateHandles());
+ updateHandles();
+
+ function updateHandles() {
+ handleElements.visible = !elem.F.disabled;
+ }
+
+ function addHandle(style, cursor, vertical, negative, vertical2, negative2) {
+ let handle = F.c("div");
+ handle.F.classList.add("ff-resizable-handle", opt.handleClass);
+ handle.F.style = style;
+ handle.style.position = "absolute";
+ handle.style.cursor = cursor;
+ elem.append(handle);
+ handleElements.add(handle);
+ handle.F.draggable({ scroll: opt.scroll, dragCursor: cursor });
+ handle.F.on("draggablestart", event => {
+ event.stopPropagation(); // Don't trigger for the resized (parent) element
+ let events = elem.F.trigger("resizablestart", { bubbles: true, cancelable: true }, {
+ vertical: vertical,
+ negative: negative,
+ edge: vertical ? (negative ? "top" : "bottom") : (negative ? "left" : "right")
+ });
+ if (events.first.defaultPrevented) {
+ event.preventDefault();
+ }
+ });
+ handle.F.on("draggablemove", event => {
+ event.stopPropagation(); // Don't trigger for the resized (parent) element
+ event.preventDefault(); // The handles already move with the element, don't touch their position
+ resize(handle, event.newPoint, vertical, negative);
+ if (vertical2 !== undefined)
+ resize(handle, event.newPoint, vertical2, negative2);
+ });
+ handle.F.on("draggableend", event => {
+ event.stopPropagation(); // Don't trigger for the resized (parent) element
+ elem.F.trigger("resizableend", { bubbles: true }, {
+ vertical: vertical,
+ negative: negative,
+ edge: vertical ? (negative ? "top" : "bottom") : (negative ? "left" : "right")
+ });
+ });
+ return handle;
+ }
+
+ function resize(handle, newPoint, vertical, negative) {
+ let side = vertical ? "top" : "left";
+ let extent = vertical ? "Height" : "Width";
+ let extentLower = extent.toLowerCase();
+ let delta = newPoint[side] - handle.F[side];
+ if (negative)
+ delta = -delta;
+
+ let newElemOffset = { left: elem.F.left, top: elem.F.top };
+ let step = opt.grid ? opt.grid[vertical ? 1 : 0] : 1;
+
+ if (opt.grid) {
+ let gridBase = {
+ left: elem.parentElement.F.left,
+ top: elem.parentElement.F.top
+ };
+ if (negative) {
+ delta = newElemOffset[side] - (Math.round(((newElemOffset[side] - delta) - gridBase[side]) / step) * step + gridBase[side]);
+ }
+ else {
+ let length = elem.F["border" + extent];
+ delta = Math.round(((newElemOffset[side] + length + delta) - gridBase[side]) / step) * step + gridBase[side] - (newElemOffset[side] + length);
+ }
+ }
+
+ let newLength = elem.F["border" + extent] + delta;
+
+ let minLength = Math.max(elem.F["border" + extent] - elem.F[extentLower], opt["min" + extent] || 0);
+ while (newLength < minLength) {
+ delta += step;
+ newLength += step;
+ }
+ let maxLength = opt["max" + extent];
+ while (maxLength && newLength > maxLength) {
+ delta -= step;
+ newLength -= step;
+ }
+
+ if (negative)
+ newElemOffset[side] -= delta;
+
+ if (opt.containment) {
+ let cont, contRect;
+ if (opt.containment === "parent") {
+ cont = elem.parentElement;
+ }
+ else if (opt.containment === "viewport") {
+ let scrollTop = window.scrollY;
+ let scrollLeft = window.scrollX;
+ contRect = {
+ top: 0 + scrollTop,
+ left: 0 + scrollLeft,
+ height: window.clientHeight,
+ width: window.clientWidth
+ };
+ }
+ else {
+ cont = F(opt.containment).first;
+ }
+ if (cont)
+ contRect = cont.F.rect;
+ if (contRect) {
+ if (negative) {
+ while (newElemOffset[side] < contRect[side]) {
+ newElemOffset[side] += step;
+ delta -= step;
+ newLength -= step;
+ }
+ }
+ else {
+ while (newElemOffset[side] + newLength > contRect[side] + contRect[extentLower]) {
+ delta -= step;
+ newLength -= step;
+ }
+ }
+ }
+ }
+
+ let events = elem.F.trigger("resizing", { bubbles: true, cancelable: true }, {
+ vertical: vertical,
+ negative: negative,
+ edge: vertical ? (negative ? "top" : "bottom") : (negative ? "left" : "right"),
+ newLength: newLength,
+ newPosition: newElemOffset[side]
+ });
+ if (!events.first.defaultPrevented) {
+ let minLength = elem.F["border" + extent] - elem.F["content" + extent];
+ // The element cannot shrink below its border+padding size
+ if (events.first.newLength < minLength) {
+ events.first.newPosition -= minLength - events.first.newLength;
+ events.first.newLength = minLength;
+ }
+ elem.F["border" + extent] = events.first.newLength;
+ if (negative) {
+ newElemOffset[side] = events.first.newPosition;
+ elem.F.left = newElemOffset.left;
+ elem.F.top = newElemOffset.top;
+ }
+ }
+ }
+ });
+}
+
+// Removes the resizing features from the elements.
+function remove() {
+ return this.forEach(elem => {
+ if (!elem.classList.contains(resizableClass)) return;
+ elem.classList.remove(resizableClass);
+ let opt = F.loadOptions("resizable", elem);
+ if (opt._wasPositionStatic)
+ elem.style.position = "static";
+ elem.F.querySelectorAll(".ff-resizable-handle").remove();
+ opt._disabledObserver.undo();
+ });
+}
+
+F.registerPlugin("resizable", resizable, {
+ defaultOptions: resizableDefaults,
+ methods: {
+ remove: remove
+ }
+});