diff --git a/doc/arraylist.html b/doc/arraylist.html index d6b20a8..62e2f3d 100644 --- a/doc/arraylist.html +++ b/doc/arraylist.html @@ -31,7 +31,7 @@

ArrayList

- Version 2.0.0-beta.3 + Version 2.0.0-rc.1

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

Breaking changes since 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

- Version 2.0.0-beta.3 + Version 2.0.0-rc.1

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 @@

DataColor

- Version 2.0.0-beta.3 + Version 2.0.0-rc.1

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 @@

Frontfire Core

- Version 2.0.0-beta.3 + Version 2.0.0-rc.1

@@ -1257,7 +1257,7 @@

left

  • left → Number
  • - 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.

    @@ -1434,7 +1434,7 @@

    top

  • top → Number
  • - 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.

    diff --git a/doc/frontfire-ui-accordion.html b/doc/frontfire-ui-accordion.html index 3a868a3..e8fdd71 100644 --- a/doc/frontfire-ui-accordion.html +++ b/doc/frontfire-ui-accordion.html @@ -24,7 +24,7 @@

    Accordion plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Autostart

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Carousel plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Frontfire UI CSS classes

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    ColorPicker plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Draggable plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Dropdown plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Form module

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Gallery plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Image module

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Installation

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Menu plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Message plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Modal plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Notification plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    OffCanvas plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Plugin options

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Page module

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Progressbar plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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: Resizable documentation + + + + + + + + + + +

    + + Frontfire documentation +
    + + + +
    +

    Resizable plugin

    +
    + Version 2.0.0-rc.1 +
    +

    + 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 +

    + +

    Description

    +

    + Resizable elements allow the user to change the width or height of an element. + Call the 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. +

    +

    + 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-”. +

    + +

    Basic examples

    +

    + 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. +

    +
    +
    +
    Resize me anywhere (if checked)
    +
    Resize me horizontally
    +
    Resize me vertically
    +
    Resize me at left edge
    +
    Resize with box handles
    +
    +

    + +

    + + +
    + +

    Minimum and maximum size

    +

    + The minimum and maximum size can be restricted while resizing the element. +

    +
    +
    +
    Minimum size
    +
    Maximum size
    +
    + + +
    + +

    Resizable within a container

    +

    + The dimensions of a resizable element can be restricted to another element or the parent element with the containment option. +

    +
    +
    +
    Resize me within the container
    +
    Resize me within the container
    +
    + + +
    + +

    Snapping to grid within the container

    +
    +
    +
    Resize me with grid snapping
    +
    Resize me horizontally with grid
    +
    + + +
    + +

    Resize event handler

    +

    + 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 top edge cannot be resized.
    • +
    • The right edge maintains a minimum element width of 120 pixels and snaps to a grid of 20 pixels.
    • +
    • The bottom and left edge are freely resizable.
    • +
    • While resizing, a CSS class is added that shows a drop shadow.
    • +
    +
    +
    +
    Resize with callback
    +
    + + +
    + +

    Options

    +

    + The following options are available: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescriptionDefault
    containmentString, 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
    gridNumber arrayThe 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
    handlesStringThe 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
    handleClassStringAdditional CSS class for the handle elements. Known class: “box”.None
    handleWidthNumberThe width of the default handles, in pixels.10
    maxHeightNumberThe maximum height to keep during resizing, in pixels.None
    maxWidthNumberThe maximum width to keep during resizing, in pixels.None
    minHeightNumberThe minimum height to keep during resizing, in pixels.None
    minWidthNumberThe minimum width to keep during resizing, in pixels.None
    scrollBooleanIndicates whether the window should scroll to keep the resized edge visible.false
    + +

    Plugin methods

    +

    + This plugin provides methods to control the resizable. +

    + +
    +

    remove

    +
      +
    • remove() → Frontfire
    • +
    +

    + Removes the resizing features from the elements. +

    +
    + +

    Plugin events

    +

    + This plugin triggers events for the resizable elements. +

    + +
    +

    resizableend

    +

    + Triggered when the resize operation has ended. + 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.
    • +
    +
    + +
    +

    resizing

    +

    + Triggered when the element is being resized. + This event can be cancelled by calling 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

    +

    + Triggered when the element is starting to be resized. + This event can be cancelled by calling 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.
    • +
    +
    +
    + +
    +
    + Copyright © 2022–2023, Yves Goergen, ygoe.de
    + All rights reserved. See the licence notes. +
    +
    + + + + diff --git a/doc/frontfire-ui-selectable.html b/doc/frontfire-ui-selectable.html index ff51845..0b70fe8 100644 --- a/doc/frontfire-ui-selectable.html +++ b/doc/frontfire-ui-selectable.html @@ -24,7 +24,7 @@

    Selectable plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Slider plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Sortable plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Table module

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Tabs plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    TimePicker plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    ToggleSwitch plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Tree plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Typography module

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Frontfire UI CSS variables

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    @@ -3087,6 +3087,39 @@

    --progress-warning-label-color

    +
    +

    --resizable-handle-box-background

    +

    + Type: color + Default: see description + (for Resizable) +

    +

    + The fill colour of a box handle of a resizable element. + The default value is:
    + var(--default-background) +

    +

    + See also: --resizable-handle-box-border +

    +
    + +
    +

    --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 +

    +
    +

    --selectable-focused-border

    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 @@

    WheelScrolling plugin

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    Frontfire Web Frontend Toolkit

    - Version 2.0.0-beta.3 + Version 2.0.0-rc.1

    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 @@

    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 + } +});