From bddabbbb4580fa94b9a11e77cce7b04bacbacc54 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:39:53 +0000 Subject: [PATCH 01/60] Update dependency eslint to v9.9.1 --- package-lock.json | 69 ++++++++++++++++++++++++++++------------------- package.json | 2 +- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/package-lock.json b/package-lock.json index 450bf0a..cbcfb10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,14 +9,13 @@ "version": "3.2.1", "license": "CC-BY-4.0", "devDependencies": { - "eslint": "9.5.0", + "eslint": "9.9.1", "eslint-plugin-html": "8.1.1", "less": "4.2.0", "standard": "17.1.0" }, "funding": { - "type": "individual", - "url": "https://github.com/sponsors/kethinov" + "url": "https://www.paypal.com/donate/?hosted_button_id=2L2X8GRXZCGJ6" } }, "node_modules/@eslint-community/eslint-utils": { @@ -47,23 +46,25 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", - "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/config-array": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.16.0.tgz", - "integrity": "sha512-/jmuSd74i4Czf1XXn7wGRWZCuyaUZ330NH1Bek0Pplatt4Sy1S5haN21SCLLdbeKslQ+S0wEJ+++v5YibSi+Lg==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.4", "debug": "^4.3.1", - "minimatch": "^3.0.5" + "minimatch": "^3.1.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -93,10 +94,11 @@ } }, "node_modules/@eslint/js": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.5.0.tgz", - "integrity": "sha512-A7+AOT2ICkodvtsWnxZP4Xxk3NbZ3VMHd8oihydLRGrJgqqdEz1qSeEgXYyT/Cu8h1TWWsQRejIx48mtjZ5y1w==", + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz", + "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -960,16 +962,17 @@ } }, "node_modules/eslint": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.5.0.tgz", - "integrity": "sha512-+NAOZFrW/jFTS3dASCGBxX1pkFD0/fsO+hfAkJ4TyYKwgsXZbqzrw+seCYFCcPCYXvnD67tAnglU7GQTz6kcVw==", + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.1.tgz", + "integrity": "sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/config-array": "^0.16.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.5.0", + "@eslint/js": "9.9.1", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", @@ -978,9 +981,9 @@ "cross-spawn": "^7.0.2", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.1", + "eslint-scope": "^8.0.2", "eslint-visitor-keys": "^4.0.0", - "espree": "^10.0.1", + "espree": "^10.1.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -1008,6 +1011,14 @@ }, "funding": { "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-import-resolver-node": { @@ -1164,10 +1175,11 @@ } }, "node_modules/eslint-scope": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", - "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -1219,12 +1231,13 @@ } }, "node_modules/espree": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", - "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.11.3", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.0.0" }, diff --git a/package.json b/package.json index 6bd0b04..edffcb2 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "dependencies": {}, "devDependencies": { "less": "4.2.0", - "eslint": "9.5.0", + "eslint": "9.9.1", "eslint-plugin-html": "8.1.1", "standard": "17.1.0" }, From 6e20af17d891418175d63f505e4ceaac5c214f2c Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Mon, 19 Aug 2024 15:19:11 -0400 Subject: [PATCH 02/60] save progress --- semanticForms copy.less | 638 ++++++++++++++++++++++++++++++++++++++++ semanticForms.css | 177 +++-------- semanticForms.js | 182 +++++++----- semanticForms.less | 210 +++---------- 4 files changed, 827 insertions(+), 380 deletions(-) create mode 100644 semanticForms copy.less diff --git a/semanticForms copy.less b/semanticForms copy.less new file mode 100644 index 0000000..55ead32 --- /dev/null +++ b/semanticForms copy.less @@ -0,0 +1,638 @@ +// #region variables + +@lightFormBackgroundColor: #fff; +@lightFormSubBackgroundColor: #f5f5f5; +@lightFormTextColor: #000; +@lightBorderColor: #c0c0c0; +@lightPlaceholderColor: #aaa; +@darkFormBackgroundColor: #555; +@darkFormSubBackgroundColor: #2f2f2f; +@darkFormSubBorderColor: #3f3f3f; +@darkFormTextColor: #fff; +@darkBorderColor: #555; +@darkPlaceholderColor: #aaa; +@darkButtonGradientLight: #6f6f6f; +@darkButtonGradientDark: #373737; + +// #endregion + +// #region default (light mode) styles + +form.semanticForms { + + // #region globals + + font-family: sans-serif; + + input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), + select, + textarea { + box-sizing: content-box; + background-color: @lightFormBackgroundColor; + outline: 0; + border: 1px @lightBorderColor solid; + border-radius: 10px; + width: 250px; + height: 25px; + font-size: 100%; + font-family: sans-serif; + padding: 5px 20px; + } + + input[type=color] { + background-color: @lightFormBackgroundColor; + border: 1px @lightBorderColor solid; + border-radius: 10px; + width: 292px; + height: 37px; + padding: 5px 20px; + } + + select { + box-sizing: border-box; + } + + input[type=range] { + border: 0 !important; + width: 248px !important; + } + + fieldset { + background-color: @lightFormSubBackgroundColor; + border: 1px @lightBorderColor solid; + border-radius: 10px; + text-align: center; + margin-bottom: 25px; + + p { + text-align: left; + width: 100%; + clear: both; + } + } + + legend { + text-align: left; + } + + dl { + text-align: left; + } + + .checkboxes ul, + .radios ul { + list-style: none; + padding: 0; + } + + dd.checkboxes, + dd.radios { + margin: 0; + } + + menu { + width: 100%; + clear: both; + display: flex; + justify-content: space-between; + padding: 0; + + li { + list-style-type: none; + } + + input[type='submit'], + input[type='reset'], + input[type='image'], + button { + float: none; + clear: none; + margin: 0; + } + } + + // #endregion + + // #region clear fields and custom select box design + + input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), + textarea { + background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23000' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); + background-size: 12px; + background-repeat: no-repeat; + } + + input:not([type=checkbox]):not([type=radio]) { + background-position: right -12px center; + } + + textarea { + background-position: right -12px top 10px; + height: 100px; + } + + select { + background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + background-size: 14px; + background-position: calc(99%) 16px; + background-repeat: no-repeat; + width: 292px; + height: 37px; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + } + + // #endregion + + // #region style placeholders + + input::placeholder { + color: @lightPlaceholderColor; + opacity: 1; + } + + textarea::placeholder { + color: @lightPlaceholderColor; + opacity: 1; + } + + input:focus::placeholder { + color: @lightPlaceholderColor; + opacity: 1; + } + + input:focus::-moz-placeholder { + color: @lightPlaceholderColor; + opacity: 1; + } + + input:focus::-webkit-input-placeholder { + color: @lightPlaceholderColor; + opacity: 1; + } + + input:focus:-ms-input-placeholder { + color: @lightPlaceholderColor; + opacity: 1; + } + + textarea:focus::placeholder { + color: @lightPlaceholderColor; + opacity: 1; + } + + textarea:focus::-moz-placeholder { + color: @lightPlaceholderColor; + opacity: 1; + } + + textarea:focus::-webkit-input-placeholder { + color: @lightPlaceholderColor; + opacity: 1; + } + + textarea:focus:-ms-input-placeholder { + color: @lightPlaceholderColor; + opacity: 1; + } + + // #endregion + + // #region buttons + + input[type='submit'], + input[type='reset'], + input[type='image'], + button { + width: auto; + box-sizing: content-box; + float: none; + clear: both; + outline: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + border-radius: 20px; + font-size: 100%; + margin: 25px 10px; + padding: 5px 25px; + border: 2px @lightBorderColor solid; + background-image: linear-gradient(to bottom, @lightFormBackgroundColor 0%, @lightBorderColor 100%); + } + + input[type='submit']:first-of-type, + input[type='reset']:first-of-type, + input[type='image']:first-of-type, + button:first-of-type { + margin-left: 0; + } + + input[type='submit']:active, + input[type='reset']:active, + input[type='image']:active, + button:active { + background-image: linear-gradient(to bottom, @lightBorderColor 0%, @lightFormBackgroundColor 100%); + } + + // #endregion + + // #region float label forms + + label.floatLabelFormAnimatedLabel, input:not([type=checkbox]):not([type=radio]), select, textarea, section { + transition: color 0.2s, text-indent 0.2s, transform 0.2s, background-position 0.2s; + touch-action: manipulation; + } + + .floatLabelForm { + margin: 0 auto; + + input[disabled] { + opacity: 0.5; + } + + // remove native clear button, we made a custom one + input:not([type=date])::-webkit-clear-button { + -webkit-appearance: none; + margin: 0; + } + + dd { + float: left; + margin: 0 10px 0 10px; + } + + dt:not(.checkboxes):not(.radios) { + font-size: 1px; + text-indent: 100%; + white-space: nowrap; + overflow: hidden; + position: absolute; + right: 9999px; + } + + dd:not(.checkboxes):not(.radios) { + display: flex; + flex-flow: column-reverse; + } + + .checkboxes ul, + .radios ul { + margin: 3px 20px 0 0; + width: 262px; + padding-left: 10px; + } + + label.floatLabelFormAnimatedLabel { + width: 170px; + padding: 6px 15px; + font-size: 75%; + color: @lightPlaceholderColor; + cursor: text; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + transform-origin: left bottom; + transform: translate(0, 38px) scale(1.5); + } + + dd:not(.checkboxes):not(.radios).singleCheckbox { + width: 292px; + display: flex; + flex-direction: row-reverse; + align-items: flex-start; + justify-content: left; + + label { + margin-top: 10px; + } + + input { + margin: 10px 10px 0 0; + } + } + + // hide placeholder content until the input is focused + ::placeholder { + opacity: 0; + transition: inherit; + } + + ::-moz-placeholder { + opacity: 0; + transition: inherit; + } + + ::-webkit-input-placeholder { + opacity: 0; + transition: inherit; + } + + :-ms-input-placeholder { + opacity: 0; + transition: inherit; + } + + // show the placeholder when the input is focused + input:focus::placeholder { + opacity: 1; + } + + input:focus::-moz-placeholder { + opacity: 1; + } + + input:focus::-webkit-input-placeholder { + opacity: 1; + } + + input:focus:-ms-input-placeholder { + opacity: 1; + } + + textarea:focus::placeholder { + opacity: 1; + } + + textarea:focus::-moz-placeholder { + opacity: 1; + } + + textarea:focus::-webkit-input-placeholder { + opacity: 1; + } + + textarea:focus:-ms-input-placeholder { + opacity: 1; + } + + // move the label off of input to make room for input content + input:not(:placeholder-shown) + label, + input:focus + label, + textarea:not(:placeholder-shown) + label, + textarea:focus + label, + select + label.floatLabelFormAnimatedLabel, + .checkboxes label.floatLabelFormAnimatedLabel, + .radios label.floatLabelFormAnimatedLabel { + transform: translate(0, 0) scale(1); + text-indent: 6px; + cursor: default; + color: @lightFormTextColor; + } + + input.x { + background-position: right 6px center; + } + + textarea.x { + background-position: right 6px top 10px; + } + + .onX { + cursor: pointer; + } + + // disable autofill yellow + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + input:-webkit-autofill:active, + textarea:-webkit-autofill, + textarea:-webkit-autofill:hover, + textarea:-webkit-autofill:focus, + textarea:-webkit-autofill:active, + select:-webkit-autofill, + select:-webkit-autofill:hover, + select:-webkit-autofill:focus, + select:-webkit-autofill:active { + -webkit-box-shadow: 0 0 0 1000px @lightFormBackgroundColor inset; + transition: background-color 5000s ease-in-out 0s, color 5000s ease-in-out 0s; + transition-delay: 5000s; + transition-property: background-color, color; + } + } + + .floatLabelForm::after { + content: " "; + visibility: hidden; + display: block; + height: 0; + clear: both; + } + + // #endregion + + // #region side-by-side pattern on large screens + + @media (min-width: 700px) { + .floatLabelForm { + margin: 0 -10px; + width: auto; + text-align: left; + } + + fieldset { + text-align: left; + + input[type='submit'], + input[type='reset'], + input[type='image'], + button { + float: left; + clear: none; + } + + :last-child { + margin-right: 0; + } + } + + .x2 { + input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), + select, + textarea { + width: 562px; + } + } + + .x2 { + input[type=color] { + width: 604px; + } + } + + .x2 { + input[type=range] { + width: 560px !important; + } + } + + .x2 { + select { + width: 604px; + } + } + + .x2.checkboxes ul, + .x2.radios ul { + width: 574px; + } + + .x2 { + label.floatLabelFormAnimatedLabel { + width: 375px; + } + } + } + + // #endregion +} + +// #endregion + +// #region non-js exclusive styles + +form.semanticForms.lowFlow { + dl { + margin: 10px 0 0 0; + } + + dd { + margin: 0 0 25px 0; + } + + dd:last-child { + margin: 0; + } +} + +// #endregion + +// #region dark mode styles + +form.semanticForms.dark { + input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), + select, + textarea { + background-color: @darkFormBackgroundColor; + border: 1px @darkBorderColor solid; + color: @darkFormTextColor; + } + + input[type=color] { + background-color: @darkFormBackgroundColor; + border: 1px @darkBorderColor solid; + color: @darkFormTextColor; + } + + fieldset { + background-color: @darkFormSubBackgroundColor; + border: 1px @darkFormSubBorderColor solid; + } + + // clear fields + input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), + textarea { + background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' stroke='%23fff' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23fff' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); + } + + // custom select box design + select { + background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + color: @darkFormTextColor; + } + + // style placeholders + input::placeholder { + color: @darkPlaceholderColor; + } + + textarea::placeholder { + color: @darkPlaceholderColor; + } + + input:focus::placeholder { + color: @darkPlaceholderColor; + } + + input:focus::-moz-placeholder { + color: @darkPlaceholderColor; + } + + input:focus::-webkit-input-placeholder { + color: @darkPlaceholderColor; + } + + input:focus:-ms-input-placeholder { + color: @darkPlaceholderColor; + } + + textarea:focus::placeholder { + color: @darkPlaceholderColor; + } + + textarea:focus::-moz-placeholder { + color: @darkPlaceholderColor; + } + + textarea:focus::-webkit-input-placeholder { + color: @darkPlaceholderColor; + } + + textarea:focus:-ms-input-placeholder { + color: @darkPlaceholderColor; + } + + // buttons + input[type='submit'], + input[type='reset'], + input[type='image'], + button { + border: 2px @darkButtonGradientDark solid; + background-image: linear-gradient(to bottom, @darkButtonGradientLight 0%, @darkButtonGradientDark 100%); + color: @darkFormTextColor; + } + + input[type='submit']:active, + input[type='reset']:active, + input[type='image']:active, + button:active { + background-image: linear-gradient(to bottom, @darkButtonGradientDark 0%, @darkButtonGradientLight 100%); + color: @darkFormTextColor; + } + + .floatLabelForm { + label.floatLabelFormAnimatedLabel { + color: @darkPlaceholderColor; + } + + // move the label off of input to make room for input content + input:not(:placeholder-shown) + label, + input:focus + label, + textarea:not(:placeholder-shown) + label, + textarea:focus + label, + select + label.floatLabelFormAnimatedLabel, + .checkboxes label.floatLabelFormAnimatedLabel, + .radios label.floatLabelFormAnimatedLabel { + color: @darkFormTextColor; + } + + // disable autofill yellow + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + input:-webkit-autofill:active, + textarea:-webkit-autofill, + textarea:-webkit-autofill:hover, + textarea:-webkit-autofill:focus, + textarea:-webkit-autofill:active, + select:-webkit-autofill, + select:-webkit-autofill:hover, + select:-webkit-autofill:focus, + select:-webkit-autofill:active { + -webkit-box-shadow: 0 0 0 1000px @darkFormBackgroundColor inset; + } + } +} + +// #endregion diff --git a/semanticForms.css b/semanticForms.css index 72ca101..fe25663 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -1,35 +1,27 @@ form.semanticForms { font-family: sans-serif; } +form.semanticForms ul { + list-style: none; + padding: 0; +} form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), form.semanticForms select, form.semanticForms textarea { - box-sizing: content-box; + box-sizing: border-box; background-color: #fff; outline: 0; border: 1px #c0c0c0 solid; - border-radius: 10px; - width: 250px; - height: 25px; - font-size: 100%; font-family: sans-serif; - padding: 5px 20px; } form.semanticForms input[type=color] { background-color: #fff; border: 1px #c0c0c0 solid; border-radius: 10px; - width: 292px; - height: 37px; - padding: 5px 20px; } form.semanticForms select { box-sizing: border-box; } -form.semanticForms input[type=range] { - border: 0 !important; - width: 248px !important; -} form.semanticForms fieldset { background-color: #f5f5f5; border: 1px #c0c0c0 solid; @@ -53,10 +45,6 @@ form.semanticForms .radios ul { list-style: none; padding: 0; } -form.semanticForms dd.checkboxes, -form.semanticForms dd.radios { - margin: 0; -} form.semanticForms menu { width: 100%; clear: both; @@ -75,15 +63,6 @@ form.semanticForms menu button { clear: none; margin: 0; } -form.semanticForms input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), -form.semanticForms textarea { - background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23000' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); - background-size: 12px; - background-repeat: no-repeat; -} -form.semanticForms input:not([type=checkbox]):not([type=radio]) { - background-position: right -12px center; -} form.semanticForms textarea { background-position: right -12px top 10px; height: 100px; @@ -93,48 +72,19 @@ form.semanticForms select { background-size: 14px; background-position: calc(99%) 16px; background-repeat: no-repeat; - width: 292px; - height: 37px; -webkit-appearance: none; -moz-appearance: none; appearance: none; } -form.semanticForms input::placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms textarea::placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms input:focus::placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms input:focus::-moz-placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms input:focus::-webkit-input-placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms input:focus:-ms-input-placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms textarea:focus::placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms textarea:focus::-moz-placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms textarea:focus::-webkit-input-placeholder { - color: #aaa; - opacity: 1; -} +form.semanticForms input::placeholder, +form.semanticForms textarea::placeholder, +form.semanticForms input:focus::placeholder, +form.semanticForms input:focus::-moz-placeholder, +form.semanticForms input:focus::-webkit-input-placeholder, +form.semanticForms input:focus:-ms-input-placeholder, +form.semanticForms textarea:focus::placeholder, +form.semanticForms textarea:focus::-moz-placeholder, +form.semanticForms textarea:focus::-webkit-input-placeholder, form.semanticForms textarea:focus:-ms-input-placeholder { color: #aaa; opacity: 1; @@ -179,7 +129,12 @@ form.semanticForms section { touch-action: manipulation; } form.semanticForms .floatLabelForm { - margin: 0 auto; + display: flex; + flex-wrap: wrap; + gap: 10px; +} +form.semanticForms .floatLabelForm div dd { + margin: 0; } form.semanticForms .floatLabelForm input[disabled] { opacity: 0.5; @@ -188,32 +143,7 @@ form.semanticForms .floatLabelForm input:not([type=date])::-webkit-clear-button -webkit-appearance: none; margin: 0; } -form.semanticForms .floatLabelForm dd { - float: left; - margin: 0 10px 0 10px; -} -form.semanticForms .floatLabelForm dt:not(.checkboxes):not(.radios) { - font-size: 1px; - text-indent: 100%; - white-space: nowrap; - overflow: hidden; - position: absolute; - right: 9999px; -} -form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios) { - display: flex; - flex-flow: column-reverse; -} -form.semanticForms .floatLabelForm .checkboxes ul, -form.semanticForms .floatLabelForm .radios ul { - margin: 3px 20px 0 0; - width: 262px; - padding-left: 10px; -} form.semanticForms .floatLabelForm label.floatLabelFormAnimatedLabel { - width: 170px; - padding: 6px 15px; - font-size: 75%; color: #aaa; cursor: text; white-space: nowrap; @@ -223,9 +153,7 @@ form.semanticForms .floatLabelForm label.floatLabelFormAnimatedLabel { transform: translate(0, 38px) scale(1.5); } form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios).singleCheckbox { - width: 292px; display: flex; - flex-direction: row-reverse; align-items: flex-start; justify-content: left; } @@ -235,43 +163,20 @@ form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios).singleCheckb form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios).singleCheckbox input { margin: 10px 10px 0 0; } -form.semanticForms .floatLabelForm ::placeholder { - opacity: 0; - transition: inherit; -} -form.semanticForms .floatLabelForm ::-moz-placeholder { +form.semanticForms .floatLabelForm ::placeholder, +form.semanticForms .floatLabelForm ::-moz-placeholder, +form.semanticForms .floatLabelForm ::-webkit-input-placeholder, +form.semanticForms .floatLabelForm ::-ms-input-placeholder { opacity: 0; transition: inherit; } -form.semanticForms .floatLabelForm ::-webkit-input-placeholder { - opacity: 0; - transition: inherit; -} -form.semanticForms .floatLabelForm :-ms-input-placeholder { - opacity: 0; - transition: inherit; -} -form.semanticForms .floatLabelForm input:focus::placeholder { - opacity: 1; -} -form.semanticForms .floatLabelForm input:focus::-moz-placeholder { - opacity: 1; -} -form.semanticForms .floatLabelForm input:focus::-webkit-input-placeholder { - opacity: 1; -} -form.semanticForms .floatLabelForm input:focus:-ms-input-placeholder { - opacity: 1; -} -form.semanticForms .floatLabelForm textarea:focus::placeholder { - opacity: 1; -} -form.semanticForms .floatLabelForm textarea:focus::-moz-placeholder { - opacity: 1; -} -form.semanticForms .floatLabelForm textarea:focus::-webkit-input-placeholder { - opacity: 1; -} +form.semanticForms .floatLabelForm input:focus::placeholder, +form.semanticForms .floatLabelForm input:focus::-moz-placeholder, +form.semanticForms .floatLabelForm input:focus::-webkit-input-placeholder, +form.semanticForms .floatLabelForm input:focus:-ms-input-placeholder, +form.semanticForms .floatLabelForm textarea:focus::placeholder, +form.semanticForms .floatLabelForm textarea:focus::-moz-placeholder, +form.semanticForms .floatLabelForm textarea:focus::-webkit-input-placeholder, form.semanticForms .floatLabelForm textarea:focus:-ms-input-placeholder { opacity: 1; } @@ -287,6 +192,15 @@ form.semanticForms .floatLabelForm .radios label.floatLabelFormAnimatedLabel { cursor: default; color: #000; } +dt label form.semanticForms .floatLabelForm input:not(:placeholder-shown) + label, +dt label form.semanticForms .floatLabelForm input:focus + label, +dt label form.semanticForms .floatLabelForm textarea:not(:placeholder-shown) + label, +dt label form.semanticForms .floatLabelForm textarea:focus + label, +dt label form.semanticForms .floatLabelForm select + label.floatLabelFormAnimatedLabel, +dt label form.semanticForms .floatLabelForm .checkboxes label.floatLabelFormAnimatedLabel, +dt label form.semanticForms .floatLabelForm .radios label.floatLabelFormAnimatedLabel { + color: red; +} form.semanticForms .floatLabelForm input.x { background-position: right 6px center; } @@ -329,13 +243,6 @@ form.semanticForms .floatLabelForm::after { form.semanticForms fieldset { text-align: left; } - form.semanticForms fieldset input[type='submit'], - form.semanticForms fieldset input[type='reset'], - form.semanticForms fieldset input[type='image'], - form.semanticForms fieldset button { - float: left; - clear: none; - } form.semanticForms fieldset :last-child { margin-right: 0; } @@ -386,10 +293,6 @@ form.semanticForms.dark fieldset { background-color: #2f2f2f; border: 1px #3f3f3f solid; } -form.semanticForms.dark input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), -form.semanticForms.dark textarea { - background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' stroke='%23fff' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23fff' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); -} form.semanticForms.dark select { background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); color: #fff; diff --git a/semanticForms.js b/semanticForms.js index 2fc5b59..f79541d 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -2,91 +2,117 @@ window.semanticForms = () => { // do some feature detection so none of the JS executes if the browser is too old if (typeof document.getElementsByClassName !== 'function' || typeof document.querySelector !== 'function' || !document.body.classList || !window.MutationObserver) return + const nodeNameLookup = ['TEXTAREA', 'SELECT'] + const typeLookup = ['checkbox', 'color', 'date', 'datetime-local', 'email', 'file', 'image', 'month', 'number', 'password', 'radio', 'range', 'search', 'tel', 'text', 'time', 'url', 'week'] + // progressively enhance form elements that have the semanticForms class const forms = document.querySelectorAll('form.semanticForms:not(.semanticFormsActive)') for (const form of forms) { form.classList.add('semanticFormsActive') - if (!form.classList.contains('lowFlow')) { - const clearfieldHorizontalOffset = parseInt(form.getAttribute('data-clearfield-horizontal-offset')) || 21 - const clearfieldVerticalOffset = parseInt(form.getAttribute('data-clearfield-vertical-offset')) || 5 - const inputs = Array.prototype.slice.call(form.getElementsByTagName('input')).concat(Array.prototype.slice.call(form.getElementsByTagName('textarea'))).concat(Array.prototype.slice.call(form.getElementsByTagName('select'))) - for (const input of inputs) { - if (input.classList.contains('semanticform')) continue - if (input.id) { - const nodeName = input.nodeName - const type = input.getAttribute('type') - if (nodeName === 'TEXTAREA' || nodeName === 'SELECT' || type === 'checkbox' || type === 'color' || type === 'date' || type === 'datetime-local' || type === 'email' || type === 'file' || type === 'image' || type === 'month' || type === 'number' || type === 'password' || type === 'radio' || type === 'range' || type === 'search' || type === 'tel' || type === 'text' || type === 'time' || type === 'url' || type === 'week') { - let dl = input.parentNode - while (dl && dl.nodeName !== 'DL') dl = dl.parentNode - if (dl) { - if (!dl.classList.contains('floatLabelForm')) dl.classList.add('floatLabelForm') - let label - if (input.parentNode.parentNode.id && (type === 'checkbox' || type === 'radio')) label = document.querySelector('label[data-for=' + input.parentNode.parentNode.id.replace(/\./g, '\\.') + ']') - else label = document.querySelector('label[for=' + input.id.replace(/\./g, '\\.') + ']') - input.classList.add('semanticform') - if (type === 'checkbox' || type === 'radio') { - dl = input.parentNode - while (dl && dl.nodeName !== 'DD') dl = dl.parentNode - if (dl.firstChild.nodeName !== 'LABEL') { - const newLabel = document.createElement('label') - newLabel.className = 'floatLabelFormAnimatedLabel' - if (type === 'checkbox' && input.parentNode.nodeName === 'DD') { - newLabel.setAttribute('for', input.id) - input.parentNode.classList.add('singleCheckbox') - newLabel.className = '' - } - newLabel.innerHTML = label.innerHTML - dl.insertBefore(newLabel, dl.firstChild) - } - } else { - const newLabel = document.createElement('label') - newLabel.setAttribute('for', input.id) - newLabel.className = 'floatLabelFormAnimatedLabel' - newLabel.innerHTML = label.innerHTML - insertAfter(newLabel, input) - label.setAttribute('hidden', 'hidden') - } - if (nodeName !== 'SELECT' && type !== 'checkbox' && type !== 'radio') { - // if it doesn't have a placeholder, add a blank one - if (!input.getAttribute('placeholder')) input.setAttribute('placeholder', ' ') - inputHandler(input) // force x to appear on inputs with prefilled value + if (form.classList.contains('lowFlow')) continue + + const clearfieldHorizontalOffset = parseInt(form.getAttribute('data-clearfield-horizontal-offset')) || 21 + const clearfieldVerticalOffset = parseInt(form.getAttribute('data-clearfield-vertical-offset')) || 5 + + // collect all form elements + const inputs = Array.from(form.querySelectorAll('input, textarea, select')) + + for (const input of inputs) { + // check if input has already been formatted + if (input.classList.contains('semanticform') || !input.id) continue + + const type = input.getAttribute('type') + + if (nodeNameLookup.includes(input.nodeName) || typeLookup.includes(type)) { + const dl = input.closest('dl') + dl.classList.toggle('floatLabelForm', true) + + let label + + if (input.parentNode.parentNode.id && (type === 'checkbox' || type === 'radio')) { + label = document.querySelector('label[data-for=' + input.parentNode.parentNode.id.replace(/\./g, '\\.') + ']') + } else { + label = document.querySelector('label[for=' + input.id.replace(/\./g, '\\.') + ']') + } + + input.classList.add('semanticform') + + // checkboxes and radios + if (type === 'checkbox' || type === 'radio') { + const dd = input.closest('dd') + if (dd.firstChild.nodeName !== 'LABEL') { + const newLabel = document.createElement('label') + newLabel.className = 'floatLabelFormAnimatedLabel' + + if (type === 'checkbox' && input.parentNode.nodeName === 'DD') { + newLabel.setAttribute('for', input.id) + input.parentNode.classList.add('singleCheckbox') + newLabel.className = '' + } + + newLabel.innerHTML = label.innerHTML + dd.append(newLabel) + } + + const div = document.createElement('div') + // removes old div that a radio or checkbox may have been added to + if (dd.parentElement.nodeName === 'DIV') { + dd.parentElement.remove() + } + div.append(label.closest('dt'), dd) + dl.append(div) + } else { + const newLabel = document.createElement('label') + newLabel.setAttribute('for', input.id) + newLabel.className = 'floatLabelFormAnimatedLabel' + newLabel.innerHTML = label.innerHTML + label.setAttribute('hidden', 'hidden') + insertAfter(newLabel, input) + // label.classList.add('floatLabelFormAnimatedLabel') + } + + // standard inputs + if (input.nodeName !== 'SELECT' && type !== 'checkbox' && type !== 'radio') { + if (!input.getAttribute('placeholder')) input.setAttribute('placeholder', ' ') + inputHandler(input) // force x to appear on inputs with prefilled value + } + + if (type !== 'checkbox' && type !== 'radio') { + const div = document.createElement('div') + div.append(label.closest('dt'), input.closest('dd')) + dl.append(div) + } + + input.addEventListener('input', inputHandler) + input.addEventListener('mousemove', event => { + const el = event.target + + if (el.nodeName === 'TEXTAREA' || typeLookup.includes(el.getAttribute('type'))) { + inputHandler(event) + if (el.offsetWidth - clearfieldHorizontalOffset < event.clientX - el.getBoundingClientRect().left && clearfieldHorizontalOffset + clearfieldVerticalOffset > event.clientY - el.getBoundingClientRect().top + ) { + if (!el.classList.contains('onX')) { + el.classList.add('onX') } - input.addEventListener('input', inputHandler) - input.addEventListener('mousemove', event => { - const el = event.target - const nodeName = el.nodeName - const type = el.getAttribute('type') - if (nodeName === 'TEXTAREA' || type === 'checkbox' || type === 'color' || type === 'date' || type === 'datetime-local' || type === 'email' || type === 'file' || type === 'month' || type === 'number' || type === 'password' || type === 'radio' || type === 'range' || type === 'search' || type === 'tel' || type === 'text' || type === 'time' || type === 'url' || type === 'week') { - inputHandler(event) - if (el.offsetWidth - clearfieldHorizontalOffset < event.clientX - el.getBoundingClientRect().left && clearfieldHorizontalOffset + clearfieldVerticalOffset > event.clientY - el.getBoundingClientRect().top - ) { - if (!el.classList.contains('onX')) { - el.classList.add('onX') - } - } else { - el.classList.remove('onX') - } - } - }) - input.addEventListener('click', event => { - const el = event.target - const nodeName = el.nodeName - const type = el.getAttribute('type') - if (nodeName === 'TEXTAREA' || type === 'color' || type === 'date' || type === 'datetime-local' || type === 'email' || type === 'file' || type === 'month' || type === 'number' || type === 'password' || type === 'search' || type === 'tel' || type === 'text' || type === 'time' || type === 'url' || type === 'week') { - if (el.offsetWidth - clearfieldHorizontalOffset < event.clientX - el.getBoundingClientRect().left && + } else { + el.classList.remove('onX') + } + } + }) + input.addEventListener('click', event => { + const el = event.target + if (el.nodeName === 'TEXTAREA' || typeLookup.includes(el.getAttribute('type'))) { + if (el.offsetWidth - clearfieldHorizontalOffset < event.clientX - el.getBoundingClientRect().left && clearfieldHorizontalOffset + clearfieldVerticalOffset > event.clientY - el.getBoundingClientRect().top - ) { - el.value = '' - el.dispatchEvent(new Event('input')) - el.form.dispatchEvent(new Event('input')) - el.classList.remove('x') - el.classList.remove('onX') - } - } - }) + ) { + el.value = '' + el.dispatchEvent(new Event('input')) + el.form.dispatchEvent(new Event('input')) + el.classList.remove('x') + el.classList.remove('onX') } } - } + }) } } } @@ -96,7 +122,7 @@ window.semanticForms = () => { const el = event.target || event const nodeName = el.nodeName const type = el.getAttribute('type') || nodeName === 'TEXTAREA' - if ((nodeName && type) && (nodeName === 'TEXTAREA' || type === 'checkbox' || type === 'color' || type === 'date' || type === 'datetime-local' || type === 'email' || type === 'file' || type === 'month' || type === 'number' || type === 'password' || type === 'radio' || type === 'range' || type === 'search' || type === 'tel' || type === 'text' || type === 'time' || type === 'url' || type === 'week')) { + if ((nodeName && type) && (nodeName === 'TEXTAREA' || typeLookup.includes(type))) { if (el.value) { if (!el.classList.contains('x')) { el.classList.add('x') diff --git a/semanticForms.less b/semanticForms.less index 55ead32..2ffa234 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -24,39 +24,31 @@ form.semanticForms { font-family: sans-serif; + ul { + list-style: none; + padding: 0; + } + input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), select, textarea { - box-sizing: content-box; + box-sizing: border-box; background-color: @lightFormBackgroundColor; outline: 0; border: 1px @lightBorderColor solid; - border-radius: 10px; - width: 250px; - height: 25px; - font-size: 100%; font-family: sans-serif; - padding: 5px 20px; } input[type=color] { background-color: @lightFormBackgroundColor; border: 1px @lightBorderColor solid; border-radius: 10px; - width: 292px; - height: 37px; - padding: 5px 20px; } select { box-sizing: border-box; } - input[type=range] { - border: 0 !important; - width: 248px !important; - } - fieldset { background-color: @lightFormSubBackgroundColor; border: 1px @lightBorderColor solid; @@ -85,11 +77,6 @@ form.semanticForms { padding: 0; } - dd.checkboxes, - dd.radios { - margin: 0; - } - menu { width: 100%; clear: both; @@ -115,17 +102,6 @@ form.semanticForms { // #region clear fields and custom select box design - input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), - textarea { - background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23000' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); - background-size: 12px; - background-repeat: no-repeat; - } - - input:not([type=checkbox]):not([type=radio]) { - background-position: right -12px center; - } - textarea { background-position: right -12px top 10px; height: 100px; @@ -136,8 +112,6 @@ form.semanticForms { background-size: 14px; background-position: calc(99%) 16px; background-repeat: no-repeat; - width: 292px; - height: 37px; -webkit-appearance: none; -moz-appearance: none; appearance: none; @@ -147,51 +121,15 @@ form.semanticForms { // #region style placeholders - input::placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } - - textarea::placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } - - input:focus::placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } - - input:focus::-moz-placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } - - input:focus::-webkit-input-placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } - - input:focus:-ms-input-placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } - - textarea:focus::placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } - - textarea:focus::-moz-placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } - - textarea:focus::-webkit-input-placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } - + input::placeholder, + textarea::placeholder, + input:focus::placeholder, + input:focus::-moz-placeholder, + input:focus::-webkit-input-placeholder, + input:focus:-ms-input-placeholder, + textarea:focus::placeholder, + textarea:focus::-moz-placeholder, + textarea:focus::-webkit-input-placeholder, textarea:focus:-ms-input-placeholder { color: @lightPlaceholderColor; opacity: 1; @@ -245,7 +183,16 @@ form.semanticForms { } .floatLabelForm { - margin: 0 auto; + display: flex; + flex-wrap: wrap; + gap: 10px; + + div { + dd { + margin: 0; + } + } + input[disabled] { opacity: 0.5; @@ -257,36 +204,7 @@ form.semanticForms { margin: 0; } - dd { - float: left; - margin: 0 10px 0 10px; - } - - dt:not(.checkboxes):not(.radios) { - font-size: 1px; - text-indent: 100%; - white-space: nowrap; - overflow: hidden; - position: absolute; - right: 9999px; - } - - dd:not(.checkboxes):not(.radios) { - display: flex; - flex-flow: column-reverse; - } - - .checkboxes ul, - .radios ul { - margin: 3px 20px 0 0; - width: 262px; - padding-left: 10px; - } - label.floatLabelFormAnimatedLabel { - width: 170px; - padding: 6px 15px; - font-size: 75%; color: @lightPlaceholderColor; cursor: text; white-space: nowrap; @@ -297,9 +215,7 @@ form.semanticForms { } dd:not(.checkboxes):not(.radios).singleCheckbox { - width: 292px; display: flex; - flex-direction: row-reverse; align-items: flex-start; justify-content: left; @@ -313,55 +229,22 @@ form.semanticForms { } // hide placeholder content until the input is focused - ::placeholder { - opacity: 0; - transition: inherit; - } - - ::-moz-placeholder { - opacity: 0; - transition: inherit; - } - - ::-webkit-input-placeholder { - opacity: 0; - transition: inherit; - } - - :-ms-input-placeholder { + ::placeholder, + ::-moz-placeholder, + ::-webkit-input-placeholder, + ::-ms-input-placeholder { opacity: 0; transition: inherit; } // show the placeholder when the input is focused - input:focus::placeholder { - opacity: 1; - } - - input:focus::-moz-placeholder { - opacity: 1; - } - - input:focus::-webkit-input-placeholder { - opacity: 1; - } - - input:focus:-ms-input-placeholder { - opacity: 1; - } - - textarea:focus::placeholder { - opacity: 1; - } - - textarea:focus::-moz-placeholder { - opacity: 1; - } - - textarea:focus::-webkit-input-placeholder { - opacity: 1; - } - + input:focus::placeholder, + input:focus::-moz-placeholder, + input:focus::-webkit-input-placeholder, + input:focus:-ms-input-placeholder, + textarea:focus::placeholder, + textarea:focus::-moz-placeholder, + textarea:focus::-webkit-input-placeholder, textarea:focus:-ms-input-placeholder { opacity: 1; } @@ -374,6 +257,11 @@ form.semanticForms { select + label.floatLabelFormAnimatedLabel, .checkboxes label.floatLabelFormAnimatedLabel, .radios label.floatLabelFormAnimatedLabel { + label & { + dt & { + color: red; + } + } transform: translate(0, 0) scale(1); text-indent: 6px; cursor: default; @@ -434,14 +322,6 @@ form.semanticForms { fieldset { text-align: left; - input[type='submit'], - input[type='reset'], - input[type='image'], - button { - float: left; - clear: none; - } - :last-child { margin-right: 0; } @@ -531,10 +411,10 @@ form.semanticForms.dark { } // clear fields - input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), - textarea { - background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' stroke='%23fff' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23fff' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); - } + // input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), + // textarea { + // background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' stroke='%23fff' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23fff' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); + // } // custom select box design select { From 31e8cc9e47f330315321fc0db5c3f216e23db617 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Wed, 21 Aug 2024 13:39:49 -0400 Subject: [PATCH 03/60] implement grid --- package-lock.json | 35 ++- package.json | 4 +- semanticForms copy.css | 279 ++++++++++++++++++ semanticForms copy.less | 476 +++++++++++++++--------------- semanticForms.css | 459 +++++++++-------------------- semanticForms.html | 12 + semanticForms.js | 35 ++- semanticForms.less | 638 +++++++++++----------------------------- 8 files changed, 898 insertions(+), 1040 deletions(-) create mode 100644 semanticForms copy.css diff --git a/package-lock.json b/package-lock.json index cbcfb10..a5c7c3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "semantic-forms", "version": "3.2.1", "license": "CC-BY-4.0", + "dependencies": { + "watch": "^1.0.2" + }, "devDependencies": { "eslint": "9.9.1", "eslint-plugin-html": "8.1.1", @@ -1290,6 +1293,15 @@ "node": ">=0.10.0" } }, + "node_modules/exec-sh": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", + "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", + "license": "MIT", + "dependencies": { + "merge": "^1.2.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2293,6 +2305,12 @@ "node": ">=6" } }, + "node_modules/merge": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", + "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", + "license": "MIT" + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -2322,7 +2340,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3742,6 +3759,22 @@ "node": ">=0.10.48" } }, + "node_modules/watch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", + "integrity": "sha512-1u+Z5n9Jc1E2c7qDO8SinPoZuHj7FgbgU1olSFoyaklduDvvtX7GMMtlE6OC9FTXq4KvNAOfj6Zu4vI1e9bAKA==", + "license": "Apache-2.0", + "dependencies": { + "exec-sh": "^0.2.0", + "minimist": "^1.2.0" + }, + "bin": { + "watch": "cli.js" + }, + "engines": { + "node": ">=0.1.95" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index edffcb2..bf73bd5 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,6 @@ "license": "CC-BY-4.0", "main": "semanticForms.js", "readmeFilename": "README.md", - "dependencies": {}, "devDependencies": { "less": "4.2.0", "eslint": "9.9.1", @@ -24,7 +23,8 @@ "coverage": "echo \"TODO: test coverage\"", "lint": "standard && standard --plugin html *.html", "lint-fix": "standard --fix && standard --plugin html *.html --fix", - "build": "lessc semanticForms.less semanticForms.css" + "build": "lessc semanticForms.less semanticForms.css", + "watch": "watch 'npm run build' ./" }, "repository": { "type": "git", diff --git a/semanticForms copy.css b/semanticForms copy.css new file mode 100644 index 0000000..37dc732 --- /dev/null +++ b/semanticForms copy.css @@ -0,0 +1,279 @@ +form.semanticForms input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), +form.semanticForms textarea { + background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23000' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); + background-size: 12px; + background-repeat: no-repeat; +} +form.semanticForms input:not([type=checkbox]):not([type=radio]) { + background-position: right -12px center; +} +form.semanticForms textarea { + background-position: right -12px top 10px; + height: 100px; +} +form.semanticForms select { + background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + background-size: 14px; + background-position: calc(99%) 16px; + background-repeat: no-repeat; + width: 292px; + height: 37px; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} +form.semanticForms input::placeholder { + color: #aaa; + opacity: 1; +} +form.semanticForms textarea::placeholder { + color: #aaa; + opacity: 1; +} +form.semanticForms input:focus::placeholder { + color: #aaa; + opacity: 1; +} +form.semanticForms input:focus::-moz-placeholder { + color: #aaa; + opacity: 1; +} +form.semanticForms input:focus::-webkit-input-placeholder { + color: #aaa; + opacity: 1; +} +form.semanticForms input:focus:-ms-input-placeholder { + color: #aaa; + opacity: 1; +} +form.semanticForms textarea:focus::placeholder { + color: #aaa; + opacity: 1; +} +form.semanticForms textarea:focus::-moz-placeholder { + color: #aaa; + opacity: 1; +} +form.semanticForms textarea:focus::-webkit-input-placeholder { + color: #aaa; + opacity: 1; +} +form.semanticForms textarea:focus:-ms-input-placeholder { + color: #aaa; + opacity: 1; +} +form.semanticForms label.floatLabelFormAnimatedLabel, +form.semanticForms input:not([type=checkbox]):not([type=radio]), +form.semanticForms select, +form.semanticForms textarea, +form.semanticForms section { + transition: color 0.2s, text-indent 0.2s, transform 0.2s, background-position 0.2s; + touch-action: manipulation; +} +form.semanticForms .floatLabelForm { + margin: 0 auto; +} +form.semanticForms .floatLabelForm input[disabled] { + opacity: 0.5; +} +form.semanticForms .floatLabelForm input:not([type=date])::-webkit-clear-button { + -webkit-appearance: none; + margin: 0; +} +form.semanticForms .floatLabelForm dd { + float: left; + margin: 0 10px 0 10px; +} +form.semanticForms .floatLabelForm dt:not(.checkboxes):not(.radios) { + font-size: 1px; + text-indent: 100%; + white-space: nowrap; + overflow: hidden; + position: absolute; + right: 9999px; +} +form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios) { + display: flex; + flex-flow: column-reverse; +} +form.semanticForms .floatLabelForm .checkboxes ul, +form.semanticForms .floatLabelForm .radios ul { + margin: 3px 20px 0 0; + width: 262px; + padding-left: 10px; +} +form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios).singleCheckbox { + width: 292px; + display: flex; + flex-direction: row-reverse; + align-items: flex-start; + justify-content: left; +} +form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios).singleCheckbox label { + margin-top: 10px; +} +form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios).singleCheckbox input { + margin: 10px 10px 0 0; +} +form.semanticForms .floatLabelForm input.x { + background-position: right 6px center; +} +form.semanticForms .floatLabelForm textarea.x { + background-position: right 6px top 10px; +} +form.semanticForms .floatLabelForm .onX { + cursor: pointer; +} +form.semanticForms .floatLabelForm input:-webkit-autofill, +form.semanticForms .floatLabelForm input:-webkit-autofill:hover, +form.semanticForms .floatLabelForm input:-webkit-autofill:focus, +form.semanticForms .floatLabelForm input:-webkit-autofill:active, +form.semanticForms .floatLabelForm textarea:-webkit-autofill, +form.semanticForms .floatLabelForm textarea:-webkit-autofill:hover, +form.semanticForms .floatLabelForm textarea:-webkit-autofill:focus, +form.semanticForms .floatLabelForm textarea:-webkit-autofill:active, +form.semanticForms .floatLabelForm select:-webkit-autofill, +form.semanticForms .floatLabelForm select:-webkit-autofill:hover, +form.semanticForms .floatLabelForm select:-webkit-autofill:focus, +form.semanticForms .floatLabelForm select:-webkit-autofill:active { + -webkit-box-shadow: 0 0 0 1000px #fff inset; + transition: background-color 5000s ease-in-out 0s, color 5000s ease-in-out 0s; + transition-delay: 5000s; + transition-property: background-color, color; +} +form.semanticForms .floatLabelForm::after { + content: " "; + visibility: hidden; + display: block; + height: 0; + clear: both; +} +@media (min-width: 700px) { + form.semanticForms .floatLabelForm { + margin: 0 -10px; + width: auto; + text-align: left; + } + form.semanticForms fieldset { + text-align: left; + } + form.semanticForms fieldset input[type='submit'], + form.semanticForms fieldset input[type='reset'], + form.semanticForms fieldset input[type='image'], + form.semanticForms fieldset button { + float: left; + clear: none; + } + form.semanticForms fieldset :last-child { + margin-right: 0; + } + form.semanticForms .x2 input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), + form.semanticForms .x2 select, + form.semanticForms .x2 textarea { + width: 562px; + } + form.semanticForms .x2 input[type=color] { + width: 604px; + } + form.semanticForms .x2 input[type=range] { + width: 560px !important; + } + form.semanticForms .x2 select { + width: 604px; + } + form.semanticForms .x2.checkboxes ul, + form.semanticForms .x2.radios ul { + width: 574px; + } + form.semanticForms .x2 label.floatLabelFormAnimatedLabel { + width: 375px; + } +} +form.semanticForms.lowFlow dl { + margin: 10px 0 0 0; +} +form.semanticForms.lowFlow dd { + margin: 0 0 25px 0; +} +form.semanticForms.lowFlow dd:last-child { + margin: 0; +} +form.semanticForms.dark input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), +form.semanticForms.dark textarea { + background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' stroke='%23fff' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23fff' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); +} +form.semanticForms.dark select { + background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + color: #fff; +} +form.semanticForms.dark input::placeholder { + color: #aaa; +} +form.semanticForms.dark textarea::placeholder { + color: #aaa; +} +form.semanticForms.dark input:focus::placeholder { + color: #aaa; +} +form.semanticForms.dark input:focus::-moz-placeholder { + color: #aaa; +} +form.semanticForms.dark input:focus::-webkit-input-placeholder { + color: #aaa; +} +form.semanticForms.dark input:focus:-ms-input-placeholder { + color: #aaa; +} +form.semanticForms.dark textarea:focus::placeholder { + color: #aaa; +} +form.semanticForms.dark textarea:focus::-moz-placeholder { + color: #aaa; +} +form.semanticForms.dark textarea:focus::-webkit-input-placeholder { + color: #aaa; +} +form.semanticForms.dark textarea:focus:-ms-input-placeholder { + color: #aaa; +} +form.semanticForms.dark input[type='submit'], +form.semanticForms.dark input[type='reset'], +form.semanticForms.dark input[type='image'], +form.semanticForms.dark button { + border: 2px #373737 solid; + background-image: linear-gradient(to bottom, #6f6f6f 0%, #373737 100%); + color: #fff; +} +form.semanticForms.dark input[type='submit']:active, +form.semanticForms.dark input[type='reset']:active, +form.semanticForms.dark input[type='image']:active, +form.semanticForms.dark button:active { + background-image: linear-gradient(to bottom, #373737 0%, #6f6f6f 100%); + color: #fff; +} +form.semanticForms.dark .floatLabelForm label.floatLabelFormAnimatedLabel { + color: #aaa; +} +form.semanticForms.dark .floatLabelForm input:not(:placeholder-shown) + label, +form.semanticForms.dark .floatLabelForm input:focus + label, +form.semanticForms.dark .floatLabelForm textarea:not(:placeholder-shown) + label, +form.semanticForms.dark .floatLabelForm textarea:focus + label, +form.semanticForms.dark .floatLabelForm select + label.floatLabelFormAnimatedLabel, +form.semanticForms.dark .floatLabelForm .checkboxes label.floatLabelFormAnimatedLabel, +form.semanticForms.dark .floatLabelForm .radios label.floatLabelFormAnimatedLabel { + color: #fff; +} +form.semanticForms.dark .floatLabelForm input:-webkit-autofill, +form.semanticForms.dark .floatLabelForm input:-webkit-autofill:hover, +form.semanticForms.dark .floatLabelForm input:-webkit-autofill:focus, +form.semanticForms.dark .floatLabelForm input:-webkit-autofill:active, +form.semanticForms.dark .floatLabelForm textarea:-webkit-autofill, +form.semanticForms.dark .floatLabelForm textarea:-webkit-autofill:hover, +form.semanticForms.dark .floatLabelForm textarea:-webkit-autofill:focus, +form.semanticForms.dark .floatLabelForm textarea:-webkit-autofill:active, +form.semanticForms.dark .floatLabelForm select:-webkit-autofill, +form.semanticForms.dark .floatLabelForm select:-webkit-autofill:hover, +form.semanticForms.dark .floatLabelForm select:-webkit-autofill:focus, +form.semanticForms.dark .floatLabelForm select:-webkit-autofill:active { + -webkit-box-shadow: 0 0 0 1000px #555 inset; +} diff --git a/semanticForms copy.less b/semanticForms copy.less index 55ead32..f0fcc33 100644 --- a/semanticForms copy.less +++ b/semanticForms copy.less @@ -22,94 +22,94 @@ form.semanticForms { // #region globals - font-family: sans-serif; - - input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), - select, - textarea { - box-sizing: content-box; - background-color: @lightFormBackgroundColor; - outline: 0; - border: 1px @lightBorderColor solid; - border-radius: 10px; - width: 250px; - height: 25px; - font-size: 100%; - font-family: sans-serif; - padding: 5px 20px; - } - - input[type=color] { - background-color: @lightFormBackgroundColor; - border: 1px @lightBorderColor solid; - border-radius: 10px; - width: 292px; - height: 37px; - padding: 5px 20px; - } - - select { - box-sizing: border-box; - } - - input[type=range] { - border: 0 !important; - width: 248px !important; - } - - fieldset { - background-color: @lightFormSubBackgroundColor; - border: 1px @lightBorderColor solid; - border-radius: 10px; - text-align: center; - margin-bottom: 25px; - - p { - text-align: left; - width: 100%; - clear: both; - } - } - - legend { - text-align: left; - } - - dl { - text-align: left; - } - - .checkboxes ul, - .radios ul { - list-style: none; - padding: 0; - } - - dd.checkboxes, - dd.radios { - margin: 0; - } - - menu { - width: 100%; - clear: both; - display: flex; - justify-content: space-between; - padding: 0; - - li { - list-style-type: none; - } - - input[type='submit'], - input[type='reset'], - input[type='image'], - button { - float: none; - clear: none; - margin: 0; - } - } + // font-family: sans-serif; + + // input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), + // select, + // textarea { + // box-sizing: content-box; + // background-color: @lightFormBackgroundColor; + // outline: 0; + // border: 1px @lightBorderColor solid; + // border-radius: 10px; + // width: 250px; + // height: 25px; + // font-size: 100%; + // font-family: sans-serif; + // padding: 5px 20px; + // } + + // input[type=color] { + // background-color: @lightFormBackgroundColor; + // border: 1px @lightBorderColor solid; + // border-radius: 10px; + // width: 292px; + // height: 37px; + // padding: 5px 20px; + // } + + // select { + // box-sizing: border-box; + // } + + // input[type=range] { + // border: 0 !important; + // width: 248px !important; + // } + + // fieldset { + // background-color: @lightFormSubBackgroundColor; + // border: 1px @lightBorderColor solid; + // border-radius: 10px; + // text-align: center; + // margin-bottom: 25px; + + // p { + // text-align: left; + // width: 100%; + // clear: both; + // } + // } + + // legend { + // text-align: left; + // } + + // dl { + // text-align: left; + // } + + // .checkboxes ul, + // .radios ul { + // list-style: none; + // padding: 0; + // } + + // dd.checkboxes, + // dd.radios { + // margin: 0; + // } + + // menu { + // width: 100%; + // clear: both; + // display: flex; + // justify-content: space-between; + // padding: 0; + + // li { + // list-style-type: none; + // } + + // input[type='submit'], + // input[type='reset'], + // input[type='image'], + // button { + // float: none; + // clear: none; + // margin: 0; + // } + // } // #endregion @@ -201,39 +201,39 @@ form.semanticForms { // #region buttons - input[type='submit'], - input[type='reset'], - input[type='image'], - button { - width: auto; - box-sizing: content-box; - float: none; - clear: both; - outline: 0; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - border-radius: 20px; - font-size: 100%; - margin: 25px 10px; - padding: 5px 25px; - border: 2px @lightBorderColor solid; - background-image: linear-gradient(to bottom, @lightFormBackgroundColor 0%, @lightBorderColor 100%); - } - - input[type='submit']:first-of-type, - input[type='reset']:first-of-type, - input[type='image']:first-of-type, - button:first-of-type { - margin-left: 0; - } - - input[type='submit']:active, - input[type='reset']:active, - input[type='image']:active, - button:active { - background-image: linear-gradient(to bottom, @lightBorderColor 0%, @lightFormBackgroundColor 100%); - } + // input[type='submit'], + // input[type='reset'], + // input[type='image'], + // button { + // width: auto; + // box-sizing: content-box; + // float: none; + // clear: both; + // outline: 0; + // -webkit-appearance: none; + // -moz-appearance: none; + // appearance: none; + // border-radius: 20px; + // font-size: 100%; + // margin: 25px 10px; + // padding: 5px 25px; + // border: 2px @lightBorderColor solid; + // background-image: linear-gradient(to bottom, @lightFormBackgroundColor 0%, @lightBorderColor 100%); + // } + + // input[type='submit']:first-of-type, + // input[type='reset']:first-of-type, + // input[type='image']:first-of-type, + // button:first-of-type { + // margin-left: 0; + // } + + // input[type='submit']:active, + // input[type='reset']:active, + // input[type='image']:active, + // button:active { + // background-image: linear-gradient(to bottom, @lightBorderColor 0%, @lightFormBackgroundColor 100%); + // } // #endregion @@ -276,109 +276,109 @@ form.semanticForms { flex-flow: column-reverse; } - .checkboxes ul, - .radios ul { - margin: 3px 20px 0 0; - width: 262px; - padding-left: 10px; - } - - label.floatLabelFormAnimatedLabel { - width: 170px; - padding: 6px 15px; - font-size: 75%; - color: @lightPlaceholderColor; - cursor: text; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - transform-origin: left bottom; - transform: translate(0, 38px) scale(1.5); - } - - dd:not(.checkboxes):not(.radios).singleCheckbox { - width: 292px; - display: flex; - flex-direction: row-reverse; - align-items: flex-start; - justify-content: left; - - label { - margin-top: 10px; - } - - input { - margin: 10px 10px 0 0; - } - } + // .checkboxes ul, + // .radios ul { + // margin: 3px 20px 0 0; + // width: 262px; + // padding-left: 10px; + // } + + // label.floatLabelFormAnimatedLabel { + // width: 170px; + // padding: 6px 15px; + // font-size: 75%; + // color: @lightPlaceholderColor; + // cursor: text; + // white-space: nowrap; + // overflow: hidden; + // text-overflow: ellipsis; + // transform-origin: left bottom; + // transform: translate(0, 38px) scale(1.5); + // } + + // dd:not(.checkboxes):not(.radios).singleCheckbox { + // width: 292px; + // display: flex; + // flex-direction: row-reverse; + // align-items: flex-start; + // justify-content: left; + + // label { + // margin-top: 10px; + // } + + // input { + // margin: 10px 10px 0 0; + // } + // } // hide placeholder content until the input is focused - ::placeholder { - opacity: 0; - transition: inherit; - } - - ::-moz-placeholder { - opacity: 0; - transition: inherit; - } - - ::-webkit-input-placeholder { - opacity: 0; - transition: inherit; - } - - :-ms-input-placeholder { - opacity: 0; - transition: inherit; - } + // ::placeholder { + // opacity: 0; + // transition: inherit; + // } + + // ::-moz-placeholder { + // opacity: 0; + // transition: inherit; + // } + + // ::-webkit-input-placeholder { + // opacity: 0; + // transition: inherit; + // } + + // :-ms-input-placeholder { + // opacity: 0; + // transition: inherit; + // } // show the placeholder when the input is focused - input:focus::placeholder { - opacity: 1; - } - - input:focus::-moz-placeholder { - opacity: 1; - } - - input:focus::-webkit-input-placeholder { - opacity: 1; - } - - input:focus:-ms-input-placeholder { - opacity: 1; - } - - textarea:focus::placeholder { - opacity: 1; - } - - textarea:focus::-moz-placeholder { - opacity: 1; - } - - textarea:focus::-webkit-input-placeholder { - opacity: 1; - } - - textarea:focus:-ms-input-placeholder { - opacity: 1; - } - - // move the label off of input to make room for input content - input:not(:placeholder-shown) + label, - input:focus + label, - textarea:not(:placeholder-shown) + label, - textarea:focus + label, - select + label.floatLabelFormAnimatedLabel, - .checkboxes label.floatLabelFormAnimatedLabel, - .radios label.floatLabelFormAnimatedLabel { - transform: translate(0, 0) scale(1); - text-indent: 6px; - cursor: default; - color: @lightFormTextColor; - } + // input:focus::placeholder { + // opacity: 1; + // } + + // input:focus::-moz-placeholder { + // opacity: 1; + // } + + // input:focus::-webkit-input-placeholder { + // opacity: 1; + // } + + // input:focus:-ms-input-placeholder { + // opacity: 1; + // } + + // textarea:focus::placeholder { + // opacity: 1; + // } + + // textarea:focus::-moz-placeholder { + // opacity: 1; + // } + + // textarea:focus::-webkit-input-placeholder { + // opacity: 1; + // } + + // textarea:focus:-ms-input-placeholder { + // opacity: 1; + // } + + // // move the label off of input to make room for input content + // input:not(:placeholder-shown) + label, + // input:focus + label, + // textarea:not(:placeholder-shown) + label, + // textarea:focus + label, + // select + label.floatLabelFormAnimatedLabel, + // .checkboxes label.floatLabelFormAnimatedLabel, + // .radios label.floatLabelFormAnimatedLabel { + // transform: translate(0, 0) scale(1); + // text-indent: 6px; + // cursor: default; + // color: @lightFormTextColor; + // } input.x { background-position: right 6px center; @@ -511,24 +511,24 @@ form.semanticForms.lowFlow { // #region dark mode styles form.semanticForms.dark { - input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), - select, - textarea { - background-color: @darkFormBackgroundColor; - border: 1px @darkBorderColor solid; - color: @darkFormTextColor; - } - - input[type=color] { - background-color: @darkFormBackgroundColor; - border: 1px @darkBorderColor solid; - color: @darkFormTextColor; - } - - fieldset { - background-color: @darkFormSubBackgroundColor; - border: 1px @darkFormSubBorderColor solid; - } + // input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), + // select, + // textarea { + // background-color: @darkFormBackgroundColor; + // border: 1px @darkBorderColor solid; + // color: @darkFormTextColor; + // } + + // input[type=color] { + // background-color: @darkFormBackgroundColor; + // border: 1px @darkBorderColor solid; + // color: @darkFormTextColor; + // } + + // fieldset { + // background-color: @darkFormSubBackgroundColor; + // border: 1px @darkFormSubBorderColor solid; + // } // clear fields input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), diff --git a/semanticForms.css b/semanticForms.css index fe25663..b30649d 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -1,370 +1,179 @@ -form.semanticForms { - font-family: sans-serif; -} -form.semanticForms ul { - list-style: none; - padding: 0; -} -form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), -form.semanticForms select, -form.semanticForms textarea { +form.semanticForms.light { + --formBackgroundColor: #fff; + --formSubBackgroundColor: #f5f5f5; + --formTextColor: #000; + --buttonBackgroundColor: #f5f5f5; + --borderColor: #c0c0c0; + --subBorderColor: #c0c0c0; + --placeholderColor: #aaa; +} +form.semanticForms.dark { + --formBackgroundColor: #555; + --formSubBackgroundColor: #2f2f2f; + --formTextColor: #fff; + --buttonBackgroundColor: #373737; + --borderColor: #555; + --subBorderColor: #3f3f3f; + --placeholderColor: #aaa; +} +form.semanticForms * { box-sizing: border-box; - background-color: #fff; - outline: 0; - border: 1px #c0c0c0 solid; + margin: 0; + padding: 0; + list-style-type: none; font-family: sans-serif; } -form.semanticForms input[type=color] { - background-color: #fff; - border: 1px #c0c0c0 solid; - border-radius: 10px; -} -form.semanticForms select { - box-sizing: border-box; +form.semanticForms { + color: var(--formTextColor); + width: 100%; } form.semanticForms fieldset { - background-color: #f5f5f5; - border: 1px #c0c0c0 solid; border-radius: 10px; - text-align: center; + padding: 20px 10px; margin-bottom: 25px; + background: var(--formSubBackgroundColor); + border: 1px var(--subBorderColor) solid; } -form.semanticForms fieldset p { - text-align: left; - width: 100%; - clear: both; +form.semanticForms fieldset dl { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 25px; +} +@media screen and (max-width: 768px) { + form.semanticForms fieldset dl { + grid-template-columns: 1fr 1fr; + } } -form.semanticForms legend { - text-align: left; +@media screen and (max-width: 450px) { + form.semanticForms fieldset dl { + grid-template-columns: 1fr; + } } -form.semanticForms dl { - text-align: left; +form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios).singleCheckbox label { + margin-top: 10px; } -form.semanticForms .checkboxes ul, -form.semanticForms .radios ul { - list-style: none; - padding: 0; +form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios).singleCheckbox input { + margin: 10px 10px 0 0; } form.semanticForms menu { - width: 100%; - clear: both; display: flex; justify-content: space-between; - padding: 0; + padding: 5px; } -form.semanticForms menu li { - list-style-type: none; +form.semanticForms dt { + position: relative; } -form.semanticForms menu input[type='submit'], -form.semanticForms menu input[type='reset'], -form.semanticForms menu input[type='image'], -form.semanticForms menu button { - float: none; - clear: none; - margin: 0; +form.semanticForms dt label[data-for="checkboxes"], +form.semanticForms dt label[data-for="radios"] { + position: absolute; + transform: translateY(-100%) scale(0.75); +} +form.semanticForms .checkboxes ul, +form.semanticForms .radios ul { + padding-left: 10px; } +form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), +form.semanticForms select, form.semanticForms textarea { - background-position: right -12px top 10px; - height: 100px; + background: var(--formBackgroundColor); + border: 1px var(--borderColor) solid; + color: var(--formTextColor); + width: 100%; + border-radius: 5px; + font-size: 16px; + padding: 8px; +} +form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):focus + label, +form.semanticForms select:focus + label, +form.semanticForms textarea:focus + label, +form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not(:placeholder-shown) + label, +form.semanticForms select:not(:placeholder-shown) + label, +form.semanticForms textarea:not(:placeholder-shown) + label { + transform: translateY(-150%) scale(0.75); } -form.semanticForms select { - background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - background-size: 14px; - background-position: calc(99%) 16px; - background-repeat: no-repeat; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; +form.semanticForms textarea { + height: 100px; } -form.semanticForms input::placeholder, -form.semanticForms textarea::placeholder, -form.semanticForms input:focus::placeholder, -form.semanticForms input:focus::-moz-placeholder, -form.semanticForms input:focus::-webkit-input-placeholder, -form.semanticForms input:focus:-ms-input-placeholder, -form.semanticForms textarea:focus::placeholder, -form.semanticForms textarea:focus::-moz-placeholder, -form.semanticForms textarea:focus::-webkit-input-placeholder, -form.semanticForms textarea:focus:-ms-input-placeholder { - color: #aaa; - opacity: 1; +form.semanticForms input[type=color] { + padding: 4px !important; + height: 38.5px; } form.semanticForms input[type='submit'], form.semanticForms input[type='reset'], form.semanticForms input[type='image'], form.semanticForms button { - width: auto; - box-sizing: content-box; - float: none; - clear: both; - outline: 0; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - border-radius: 20px; - font-size: 100%; - margin: 25px 10px; - padding: 5px 25px; - border: 2px #c0c0c0 solid; - background-image: linear-gradient(to bottom, #fff 0%, #c0c0c0 100%); -} -form.semanticForms input[type='submit']:first-of-type, -form.semanticForms input[type='reset']:first-of-type, -form.semanticForms input[type='image']:first-of-type, -form.semanticForms button:first-of-type { - margin-left: 0; -} -form.semanticForms input[type='submit']:active, -form.semanticForms input[type='reset']:active, -form.semanticForms input[type='image']:active, -form.semanticForms button:active { - background-image: linear-gradient(to bottom, #c0c0c0 0%, #fff 100%); -} -form.semanticForms label.floatLabelFormAnimatedLabel, -form.semanticForms input:not([type=checkbox]):not([type=radio]), -form.semanticForms select, -form.semanticForms textarea, -form.semanticForms section { - transition: color 0.2s, text-indent 0.2s, transform 0.2s, background-position 0.2s; - touch-action: manipulation; -} -form.semanticForms .floatLabelForm { - display: flex; - flex-wrap: wrap; - gap: 10px; -} -form.semanticForms .floatLabelForm div dd { - margin: 0; + background: var(--buttonBackgroundColor); + border-radius: 5px; + padding: 5px; + color: var(--formTextColor); + border: 2px var(--borderColor) solid; } -form.semanticForms .floatLabelForm input[disabled] { - opacity: 0.5; +form.semanticForms label { + color: var(--placeholderColor); } -form.semanticForms .floatLabelForm input:not([type=date])::-webkit-clear-button { - -webkit-appearance: none; - margin: 0; +form.semanticForms input::placeholder, +form.semanticForms textarea::placeholder { + color: var(--placeholderColor); + opacity: 1; } -form.semanticForms .floatLabelForm label.floatLabelFormAnimatedLabel { - color: #aaa; +form.semanticForms input:not(:placeholder-shown) + label, +form.semanticForms input:focus + label, +form.semanticForms textarea:not(:placeholder-shown) + label, +form.semanticForms textarea:focus + label, +form.semanticForms select + label.floatLabelFormAnimatedLabel, +form.semanticForms .checkboxes label.floatLabelFormAnimatedLabel, +form.semanticForms .radios label.floatLabelFormAnimatedLabel, +form.semanticForms dt > label { + color: var(--formTextColor); +} +form.semanticForms .floatLabelForm div { + position: relative; +} +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) > label { + position: absolute; + transform-origin: left center; + pointer-events: none; + top: 8px; + left: 8px; + transition: transform 250ms; cursor: text; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - transform-origin: left bottom; - transform: translate(0, 38px) scale(1.5); } -form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios).singleCheckbox { - display: flex; - align-items: flex-start; - justify-content: left; +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input::placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea::placeholder { + opacity: 0; + transition: inherit; } -form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios).singleCheckbox label { - margin-top: 10px; +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input::-moz-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea::-moz-placeholder { + opacity: 0; + transition: inherit; } -form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios).singleCheckbox input { - margin: 10px 10px 0 0; +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input::-webkit-input-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea::-webkit-input-placeholder { + opacity: 0; + transition: inherit; } -form.semanticForms .floatLabelForm ::placeholder, -form.semanticForms .floatLabelForm ::-moz-placeholder, -form.semanticForms .floatLabelForm ::-webkit-input-placeholder, -form.semanticForms .floatLabelForm ::-ms-input-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input:-ms-input-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea:-ms-input-placeholder { opacity: 0; transition: inherit; } -form.semanticForms .floatLabelForm input:focus::placeholder, -form.semanticForms .floatLabelForm input:focus::-moz-placeholder, -form.semanticForms .floatLabelForm input:focus::-webkit-input-placeholder, -form.semanticForms .floatLabelForm input:focus:-ms-input-placeholder, -form.semanticForms .floatLabelForm textarea:focus::placeholder, -form.semanticForms .floatLabelForm textarea:focus::-moz-placeholder, -form.semanticForms .floatLabelForm textarea:focus::-webkit-input-placeholder, -form.semanticForms .floatLabelForm textarea:focus:-ms-input-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input:focus::placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea:focus::placeholder { opacity: 1; } -form.semanticForms .floatLabelForm input:not(:placeholder-shown) + label, -form.semanticForms .floatLabelForm input:focus + label, -form.semanticForms .floatLabelForm textarea:not(:placeholder-shown) + label, -form.semanticForms .floatLabelForm textarea:focus + label, -form.semanticForms .floatLabelForm select + label.floatLabelFormAnimatedLabel, -form.semanticForms .floatLabelForm .checkboxes label.floatLabelFormAnimatedLabel, -form.semanticForms .floatLabelForm .radios label.floatLabelFormAnimatedLabel { - transform: translate(0, 0) scale(1); - text-indent: 6px; - cursor: default; - color: #000; -} -dt label form.semanticForms .floatLabelForm input:not(:placeholder-shown) + label, -dt label form.semanticForms .floatLabelForm input:focus + label, -dt label form.semanticForms .floatLabelForm textarea:not(:placeholder-shown) + label, -dt label form.semanticForms .floatLabelForm textarea:focus + label, -dt label form.semanticForms .floatLabelForm select + label.floatLabelFormAnimatedLabel, -dt label form.semanticForms .floatLabelForm .checkboxes label.floatLabelFormAnimatedLabel, -dt label form.semanticForms .floatLabelForm .radios label.floatLabelFormAnimatedLabel { - color: red; -} -form.semanticForms .floatLabelForm input.x { - background-position: right 6px center; -} -form.semanticForms .floatLabelForm textarea.x { - background-position: right 6px top 10px; -} -form.semanticForms .floatLabelForm .onX { - cursor: pointer; -} -form.semanticForms .floatLabelForm input:-webkit-autofill, -form.semanticForms .floatLabelForm input:-webkit-autofill:hover, -form.semanticForms .floatLabelForm input:-webkit-autofill:focus, -form.semanticForms .floatLabelForm input:-webkit-autofill:active, -form.semanticForms .floatLabelForm textarea:-webkit-autofill, -form.semanticForms .floatLabelForm textarea:-webkit-autofill:hover, -form.semanticForms .floatLabelForm textarea:-webkit-autofill:focus, -form.semanticForms .floatLabelForm textarea:-webkit-autofill:active, -form.semanticForms .floatLabelForm select:-webkit-autofill, -form.semanticForms .floatLabelForm select:-webkit-autofill:hover, -form.semanticForms .floatLabelForm select:-webkit-autofill:focus, -form.semanticForms .floatLabelForm select:-webkit-autofill:active { - -webkit-box-shadow: 0 0 0 1000px #fff inset; - transition: background-color 5000s ease-in-out 0s, color 5000s ease-in-out 0s; - transition-delay: 5000s; - transition-property: background-color, color; -} -form.semanticForms .floatLabelForm::after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -@media (min-width: 700px) { - form.semanticForms .floatLabelForm { - margin: 0 -10px; - width: auto; - text-align: left; - } - form.semanticForms fieldset { - text-align: left; - } - form.semanticForms fieldset :last-child { - margin-right: 0; - } - form.semanticForms .x2 input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), - form.semanticForms .x2 select, - form.semanticForms .x2 textarea { - width: 562px; - } - form.semanticForms .x2 input[type=color] { - width: 604px; - } - form.semanticForms .x2 input[type=range] { - width: 560px !important; - } - form.semanticForms .x2 select { - width: 604px; - } - form.semanticForms .x2.checkboxes ul, - form.semanticForms .x2.radios ul { - width: 574px; - } - form.semanticForms .x2 label.floatLabelFormAnimatedLabel { - width: 375px; - } -} -form.semanticForms.lowFlow dl { - margin: 10px 0 0 0; -} -form.semanticForms.lowFlow dd { - margin: 0 0 25px 0; +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input:focus::-moz-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea:focus::-moz-placeholder { + opacity: 1; } -form.semanticForms.lowFlow dd:last-child { - margin: 0; +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input:focus::-webkit-input-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea:focus::-webkit-input-placeholder { + opacity: 1; } -form.semanticForms.dark input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), -form.semanticForms.dark select, -form.semanticForms.dark textarea { - background-color: #555; - border: 1px #555 solid; - color: #fff; -} -form.semanticForms.dark input[type=color] { - background-color: #555; - border: 1px #555 solid; - color: #fff; -} -form.semanticForms.dark fieldset { - background-color: #2f2f2f; - border: 1px #3f3f3f solid; -} -form.semanticForms.dark select { - background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - color: #fff; -} -form.semanticForms.dark input::placeholder { - color: #aaa; -} -form.semanticForms.dark textarea::placeholder { - color: #aaa; -} -form.semanticForms.dark input:focus::placeholder { - color: #aaa; -} -form.semanticForms.dark input:focus::-moz-placeholder { - color: #aaa; -} -form.semanticForms.dark input:focus::-webkit-input-placeholder { - color: #aaa; -} -form.semanticForms.dark input:focus:-ms-input-placeholder { - color: #aaa; -} -form.semanticForms.dark textarea:focus::placeholder { - color: #aaa; -} -form.semanticForms.dark textarea:focus::-moz-placeholder { - color: #aaa; -} -form.semanticForms.dark textarea:focus::-webkit-input-placeholder { - color: #aaa; -} -form.semanticForms.dark textarea:focus:-ms-input-placeholder { - color: #aaa; -} -form.semanticForms.dark input[type='submit'], -form.semanticForms.dark input[type='reset'], -form.semanticForms.dark input[type='image'], -form.semanticForms.dark button { - border: 2px #373737 solid; - background-image: linear-gradient(to bottom, #6f6f6f 0%, #373737 100%); - color: #fff; -} -form.semanticForms.dark input[type='submit']:active, -form.semanticForms.dark input[type='reset']:active, -form.semanticForms.dark input[type='image']:active, -form.semanticForms.dark button:active { - background-image: linear-gradient(to bottom, #373737 0%, #6f6f6f 100%); - color: #fff; -} -form.semanticForms.dark .floatLabelForm label.floatLabelFormAnimatedLabel { - color: #aaa; -} -form.semanticForms.dark .floatLabelForm input:not(:placeholder-shown) + label, -form.semanticForms.dark .floatLabelForm input:focus + label, -form.semanticForms.dark .floatLabelForm textarea:not(:placeholder-shown) + label, -form.semanticForms.dark .floatLabelForm textarea:focus + label, -form.semanticForms.dark .floatLabelForm select + label.floatLabelFormAnimatedLabel, -form.semanticForms.dark .floatLabelForm .checkboxes label.floatLabelFormAnimatedLabel, -form.semanticForms.dark .floatLabelForm .radios label.floatLabelFormAnimatedLabel { - color: #fff; -} -form.semanticForms.dark .floatLabelForm input:-webkit-autofill, -form.semanticForms.dark .floatLabelForm input:-webkit-autofill:hover, -form.semanticForms.dark .floatLabelForm input:-webkit-autofill:focus, -form.semanticForms.dark .floatLabelForm input:-webkit-autofill:active, -form.semanticForms.dark .floatLabelForm textarea:-webkit-autofill, -form.semanticForms.dark .floatLabelForm textarea:-webkit-autofill:hover, -form.semanticForms.dark .floatLabelForm textarea:-webkit-autofill:focus, -form.semanticForms.dark .floatLabelForm textarea:-webkit-autofill:active, -form.semanticForms.dark .floatLabelForm select:-webkit-autofill, -form.semanticForms.dark .floatLabelForm select:-webkit-autofill:hover, -form.semanticForms.dark .floatLabelForm select:-webkit-autofill:focus, -form.semanticForms.dark .floatLabelForm select:-webkit-autofill:active { - -webkit-box-shadow: 0 0 0 1000px #555 inset; +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input:focus:-ms-input-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea:focus:-ms-input-placeholder { + opacity: 1; } diff --git a/semanticForms.html b/semanticForms.html index b706583..a4dd2e2 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -122,6 +122,18 @@

Semantic Forms

+
+ Nested fieldset + +
+
+
+ +

Here is some subtext.

+
+
+
+ diff --git a/semanticForms.js b/semanticForms.js index f79541d..56c58e5 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -7,16 +7,37 @@ window.semanticForms = () => { // progressively enhance form elements that have the semanticForms class const forms = document.querySelectorAll('form.semanticForms:not(.semanticFormsActive)') + for (const form of forms) { form.classList.add('semanticFormsActive') - if (form.classList.contains('lowFlow')) continue - - const clearfieldHorizontalOffset = parseInt(form.getAttribute('data-clearfield-horizontal-offset')) || 21 - const clearfieldVerticalOffset = parseInt(form.getAttribute('data-clearfield-vertical-offset')) || 5 // collect all form elements const inputs = Array.from(form.querySelectorAll('input, textarea, select')) + if (form.classList.contains('lowFlow')) { + for (const input of inputs) { + const dl = input.closest('dl') + const dt = input.closest('dd')?.previousElementSibling + const dd = input.closest('dd') + + if (dt && dt.nodeName === 'DT' && dd.nodeName === 'DD') { + // removes old div that a radio or checkbox may have been added to + if (dd.parentElement.nodeName === 'DIV') { + dd.parentElement.remove() + } + + const div = document.createElement('div') + div.append(dt, dd) + dl.append(div) + } + } + console.log('low flow') + continue + } + + const clearfieldHorizontalOffset = parseInt(form.getAttribute('data-clearfield-horizontal-offset')) || 21 + const clearfieldVerticalOffset = parseInt(form.getAttribute('data-clearfield-vertical-offset')) || 5 + for (const input of inputs) { // check if input has already been formatted if (input.classList.contains('semanticform') || !input.id) continue @@ -48,10 +69,13 @@ window.semanticForms = () => { newLabel.setAttribute('for', input.id) input.parentNode.classList.add('singleCheckbox') newLabel.className = '' + label.setAttribute('hidden', 'hidden') } newLabel.innerHTML = label.innerHTML - dd.append(newLabel) + if (!dd.querySelector('label')) { + dd.append(newLabel) + } } const div = document.createElement('div') @@ -68,7 +92,6 @@ window.semanticForms = () => { newLabel.innerHTML = label.innerHTML label.setAttribute('hidden', 'hidden') insertAfter(newLabel, input) - // label.classList.add('floatLabelFormAnimatedLabel') } // standard inputs diff --git a/semanticForms.less b/semanticForms.less index 2ffa234..81d42b1 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -1,518 +1,220 @@ -// #region variables - -@lightFormBackgroundColor: #fff; -@lightFormSubBackgroundColor: #f5f5f5; -@lightFormTextColor: #000; -@lightBorderColor: #c0c0c0; -@lightPlaceholderColor: #aaa; -@darkFormBackgroundColor: #555; -@darkFormSubBackgroundColor: #2f2f2f; -@darkFormSubBorderColor: #3f3f3f; -@darkFormTextColor: #fff; -@darkBorderColor: #555; -@darkPlaceholderColor: #aaa; -@darkButtonGradientLight: #6f6f6f; -@darkButtonGradientDark: #373737; - -// #endregion - -// #region default (light mode) styles - -form.semanticForms { +// setup global colors +form.semanticForms.light { + --formBackgroundColor: #fff; + --formSubBackgroundColor: #f5f5f5; + --formTextColor: #000; + --buttonBackgroundColor: #f5f5f5; + --borderColor: #c0c0c0; + --subBorderColor: #c0c0c0; + --placeholderColor: #aaa; +} - // #region globals +form.semanticForms.dark { + --formBackgroundColor: #555; + --formSubBackgroundColor: #2f2f2f; + --formTextColor: #fff; + --buttonBackgroundColor: #373737; + --borderColor: #555; + --subBorderColor: #3f3f3f; + --placeholderColor: #aaa; +} +// global override +form.semanticForms * { + box-sizing: border-box; + margin: 0; + padding: 0; + list-style-type: none; font-family: sans-serif; +} - ul { - list-style: none; - padding: 0; - } - - input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), - select, - textarea { - box-sizing: border-box; - background-color: @lightFormBackgroundColor; - outline: 0; - border: 1px @lightBorderColor solid; - font-family: sans-serif; - } - - input[type=color] { - background-color: @lightFormBackgroundColor; - border: 1px @lightBorderColor solid; - border-radius: 10px; - } - - select { - box-sizing: border-box; - } +form.semanticForms { + color: var(--formTextColor); + width: 100%; fieldset { - background-color: @lightFormSubBackgroundColor; - border: 1px @lightBorderColor solid; border-radius: 10px; - text-align: center; + padding: 20px 10px; margin-bottom: 25px; + background: var(--formSubBackgroundColor); + border: 1px var(--subBorderColor) solid; - p { - text-align: left; - width: 100%; - clear: both; - } - } - - legend { - text-align: left; - } - - dl { - text-align: left; - } - - .checkboxes ul, - .radios ul { - list-style: none; - padding: 0; - } - - menu { - width: 100%; - clear: both; - display: flex; - justify-content: space-between; - padding: 0; - - li { - list-style-type: none; - } - - input[type='submit'], - input[type='reset'], - input[type='image'], - button { - float: none; - clear: none; - margin: 0; - } - } - - // #endregion - - // #region clear fields and custom select box design - - textarea { - background-position: right -12px top 10px; - height: 100px; - } - - select { - background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - background-size: 14px; - background-position: calc(99%) 16px; - background-repeat: no-repeat; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - } - - // #endregion - - // #region style placeholders - - input::placeholder, - textarea::placeholder, - input:focus::placeholder, - input:focus::-moz-placeholder, - input:focus::-webkit-input-placeholder, - input:focus:-ms-input-placeholder, - textarea:focus::placeholder, - textarea:focus::-moz-placeholder, - textarea:focus::-webkit-input-placeholder, - textarea:focus:-ms-input-placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } - - // #endregion - - // #region buttons - - input[type='submit'], - input[type='reset'], - input[type='image'], - button { - width: auto; - box-sizing: content-box; - float: none; - clear: both; - outline: 0; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - border-radius: 20px; - font-size: 100%; - margin: 25px 10px; - padding: 5px 25px; - border: 2px @lightBorderColor solid; - background-image: linear-gradient(to bottom, @lightFormBackgroundColor 0%, @lightBorderColor 100%); - } + dl { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 25px; - input[type='submit']:first-of-type, - input[type='reset']:first-of-type, - input[type='image']:first-of-type, - button:first-of-type { - margin-left: 0; - } - - input[type='submit']:active, - input[type='reset']:active, - input[type='image']:active, - button:active { - background-image: linear-gradient(to bottom, @lightBorderColor 0%, @lightFormBackgroundColor 100%); - } - - // #endregion - - // #region float label forms - - label.floatLabelFormAnimatedLabel, input:not([type=checkbox]):not([type=radio]), select, textarea, section { - transition: color 0.2s, text-indent 0.2s, transform 0.2s, background-position 0.2s; - touch-action: manipulation; - } - - .floatLabelForm { - display: flex; - flex-wrap: wrap; - gap: 10px; - - div { - dd { - margin: 0; - } - } - - - input[disabled] { - opacity: 0.5; - } - - // remove native clear button, we made a custom one - input:not([type=date])::-webkit-clear-button { - -webkit-appearance: none; - margin: 0; - } - - label.floatLabelFormAnimatedLabel { - color: @lightPlaceholderColor; - cursor: text; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - transform-origin: left bottom; - transform: translate(0, 38px) scale(1.5); - } - - dd:not(.checkboxes):not(.radios).singleCheckbox { - display: flex; - align-items: flex-start; - justify-content: left; - - label { - margin-top: 10px; + @media screen and (max-width: 768px) { + grid-template-columns: 1fr 1fr; } - input { - margin: 10px 10px 0 0; + @media screen and (max-width: 450px) { + grid-template-columns: 1fr; } - } - - // hide placeholder content until the input is focused - ::placeholder, - ::-moz-placeholder, - ::-webkit-input-placeholder, - ::-ms-input-placeholder { - opacity: 0; - transition: inherit; - } - // show the placeholder when the input is focused - input:focus::placeholder, - input:focus::-moz-placeholder, - input:focus::-webkit-input-placeholder, - input:focus:-ms-input-placeholder, - textarea:focus::placeholder, - textarea:focus::-moz-placeholder, - textarea:focus::-webkit-input-placeholder, - textarea:focus:-ms-input-placeholder { - opacity: 1; - } + dd:not(.checkboxes):not(.radios).singleCheckbox { + label { + margin-top: 10px; + } - // move the label off of input to make room for input content - input:not(:placeholder-shown) + label, - input:focus + label, - textarea:not(:placeholder-shown) + label, - textarea:focus + label, - select + label.floatLabelFormAnimatedLabel, - .checkboxes label.floatLabelFormAnimatedLabel, - .radios label.floatLabelFormAnimatedLabel { - label & { - dt & { - color: red; + input { + margin: 10px 10px 0 0; } } - transform: translate(0, 0) scale(1); - text-indent: 6px; - cursor: default; - color: @lightFormTextColor; - } - - input.x { - background-position: right 6px center; - } - - textarea.x { - background-position: right 6px top 10px; - } - - .onX { - cursor: pointer; - } - - // disable autofill yellow - input:-webkit-autofill, - input:-webkit-autofill:hover, - input:-webkit-autofill:focus, - input:-webkit-autofill:active, - textarea:-webkit-autofill, - textarea:-webkit-autofill:hover, - textarea:-webkit-autofill:focus, - textarea:-webkit-autofill:active, - select:-webkit-autofill, - select:-webkit-autofill:hover, - select:-webkit-autofill:focus, - select:-webkit-autofill:active { - -webkit-box-shadow: 0 0 0 1000px @lightFormBackgroundColor inset; - transition: background-color 5000s ease-in-out 0s, color 5000s ease-in-out 0s; - transition-delay: 5000s; - transition-property: background-color, color; } } - .floatLabelForm::after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; + menu { + display: flex; + justify-content: space-between; + padding: 5px; } - // #endregion + // adjust checkbox and radios labels + dt { + position: relative; - // #region side-by-side pattern on large screens - - @media (min-width: 700px) { - .floatLabelForm { - margin: 0 -10px; - width: auto; - text-align: left; - } - - fieldset { - text-align: left; - - :last-child { - margin-right: 0; - } - } - - .x2 { - input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), - select, - textarea { - width: 562px; - } - } - - .x2 { - input[type=color] { - width: 604px; - } - } - - .x2 { - input[type=range] { - width: 560px !important; - } - } - - .x2 { - select { - width: 604px; - } + label[data-for="checkboxes"], + label[data-for="radios"] { + position: absolute; + transform: translateY(-100%) scale(0.75); } - - .x2.checkboxes ul, - .x2.radios ul { - width: 574px; - } - - .x2 { - label.floatLabelFormAnimatedLabel { - width: 375px; - } - } - } - - // #endregion -} - -// #endregion - -// #region non-js exclusive styles - -form.semanticForms.lowFlow { - dl { - margin: 10px 0 0 0; } - dd { - margin: 0 0 25px 0; - } - - dd:last-child { - margin: 0; + .checkboxes ul, + .radios ul { + padding-left: 10px; } -} - -// #endregion -// #region dark mode styles - -form.semanticForms.dark { - input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), + // style all input types + input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), select, textarea { - background-color: @darkFormBackgroundColor; - border: 1px @darkBorderColor solid; - color: @darkFormTextColor; - } - - input[type=color] { - background-color: @darkFormBackgroundColor; - border: 1px @darkBorderColor solid; - color: @darkFormTextColor; - } - - fieldset { - background-color: @darkFormSubBackgroundColor; - border: 1px @darkFormSubBorderColor solid; - } - - // clear fields - // input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), - // textarea { - // background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' stroke='%23fff' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23fff' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); - // } - - // custom select box design - select { - background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - color: @darkFormTextColor; - } - - // style placeholders - input::placeholder { - color: @darkPlaceholderColor; - } - - textarea::placeholder { - color: @darkPlaceholderColor; - } - - input:focus::placeholder { - color: @darkPlaceholderColor; - } - - input:focus::-moz-placeholder { - color: @darkPlaceholderColor; - } - - input:focus::-webkit-input-placeholder { - color: @darkPlaceholderColor; - } - - input:focus:-ms-input-placeholder { - color: @darkPlaceholderColor; - } - - textarea:focus::placeholder { - color: @darkPlaceholderColor; - } + background: var(--formBackgroundColor); + border: 1px var(--borderColor) solid; + color: var(--formTextColor); + width: 100%; + border-radius: 5px; + font-size: 16px; + padding: 8px; - textarea:focus::-moz-placeholder { - color: @darkPlaceholderColor; + &:focus + label, + &:not(:placeholder-shown) + label { + transform: translateY(-150%) scale(0.75); + } } - textarea:focus::-webkit-input-placeholder { - color: @darkPlaceholderColor; + textarea { + height: 100px; } - textarea:focus:-ms-input-placeholder { - color: @darkPlaceholderColor; + // specific styling for color + input[type=color] { + padding: 4px !important; + height: 38.5px; } - // buttons + // button styling input[type='submit'], input[type='reset'], input[type='image'], button { - border: 2px @darkButtonGradientDark solid; - background-image: linear-gradient(to bottom, @darkButtonGradientLight 0%, @darkButtonGradientDark 100%); - color: @darkFormTextColor; + background: var(--buttonBackgroundColor); + color: var(--formTextColor); + border-radius: 5px; + padding: 5px; + color: var(--formTextColor); + border: 2px var(--borderColor) solid; } - input[type='submit']:active, - input[type='reset']:active, - input[type='image']:active, - button:active { - background-image: linear-gradient(to bottom, @darkButtonGradientDark 0%, @darkButtonGradientLight 100%); - color: @darkFormTextColor; + label { + color: var(--placeholderColor); } - .floatLabelForm { - label.floatLabelFormAnimatedLabel { - color: @darkPlaceholderColor; - } + // select { + // background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + // } - // move the label off of input to make room for input content - input:not(:placeholder-shown) + label, - input:focus + label, - textarea:not(:placeholder-shown) + label, - textarea:focus + label, - select + label.floatLabelFormAnimatedLabel, - .checkboxes label.floatLabelFormAnimatedLabel, - .radios label.floatLabelFormAnimatedLabel { - color: @darkFormTextColor; + // style placeholders + input, textarea { + &::placeholder { + color: var(--placeholderColor); + opacity: 1; } + } - // disable autofill yellow - input:-webkit-autofill, - input:-webkit-autofill:hover, - input:-webkit-autofill:focus, - input:-webkit-autofill:active, - textarea:-webkit-autofill, - textarea:-webkit-autofill:hover, - textarea:-webkit-autofill:focus, - textarea:-webkit-autofill:active, - select:-webkit-autofill, - select:-webkit-autofill:hover, - select:-webkit-autofill:focus, - select:-webkit-autofill:active { - -webkit-box-shadow: 0 0 0 1000px @darkFormBackgroundColor inset; - } + input:not(:placeholder-shown) + label, + input:focus + label, + textarea:not(:placeholder-shown) + label, + textarea:focus + label, + select + label.floatLabelFormAnimatedLabel, + .checkboxes label.floatLabelFormAnimatedLabel, + .radios label.floatLabelFormAnimatedLabel, + dt > label { + color: var(--formTextColor); } -} -// #endregion + // animated labels + .floatLabelForm { + div { + position: relative; + + dd:not(.singleCheckbox) { + > label { + position: absolute; + transform-origin: left center; + pointer-events: none; + top: 8px; + left: 8px; + transition: transform 250ms; + cursor: text; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + input, textarea { + // hide placeholder content until input is focused + &::placeholder { + opacity: 0; + transition: inherit; + } + + &::-moz-placeholder { + opacity: 0; + transition: inherit; + } + + &::-webkit-input-placeholder { + opacity: 0; + transition: inherit; + } + + &:-ms-input-placeholder { + opacity: 0; + transition: inherit; + } + + // show placeholder content when focused + &:focus { + &::placeholder { + opacity: 1; + } + + &::-moz-placeholder { + opacity: 1; + } + + &::-webkit-input-placeholder { + opacity: 1; + } + + &:-ms-input-placeholder { + opacity: 1; + } + } + } + } + } + } +} \ No newline at end of file From 96c727aebb261adcf659929a02061d8873bd7fa9 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Thu, 22 Aug 2024 08:22:53 -0400 Subject: [PATCH 04/60] add clear button --- semanticForms copy.less | 24 ++++++++++---------- semanticForms.css | 38 ++++++++++++++++++++++++++++++++ semanticForms.html | 12 ++++++++++ semanticForms.js | 40 ++++++++++++++++----------------- semanticForms.less | 49 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+), 33 deletions(-) diff --git a/semanticForms copy.less b/semanticForms copy.less index f0fcc33..681a9a0 100644 --- a/semanticForms copy.less +++ b/semanticForms copy.less @@ -262,19 +262,19 @@ form.semanticForms { margin: 0 10px 0 10px; } - dt:not(.checkboxes):not(.radios) { - font-size: 1px; - text-indent: 100%; - white-space: nowrap; - overflow: hidden; - position: absolute; - right: 9999px; - } + // dt:not(.checkboxes):not(.radios) { + // font-size: 1px; + // text-indent: 100%; + // white-space: nowrap; + // overflow: hidden; + // position: absolute; + // right: 9999px; + // } - dd:not(.checkboxes):not(.radios) { - display: flex; - flex-flow: column-reverse; - } + // dd:not(.checkboxes):not(.radios) { + // display: flex; + // flex-flow: column-reverse; + // } // .checkboxes ul, // .radios ul { diff --git a/semanticForms.css b/semanticForms.css index b30649d..b64cf61 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -55,6 +55,11 @@ form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios).singleCheckbox l form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios).singleCheckbox input { margin: 10px 10px 0 0; } +form.semanticForms.lowFlow fieldset dl { + display: flex; + flex-direction: column; + gap: 5px; +} form.semanticForms menu { display: flex; justify-content: space-between; @@ -72,6 +77,9 @@ form.semanticForms .checkboxes ul, form.semanticForms .radios ul { padding-left: 10px; } +form.semanticForms dd { + position: relative; +} form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), form.semanticForms select, form.semanticForms textarea { @@ -82,6 +90,7 @@ form.semanticForms textarea { border-radius: 5px; font-size: 16px; padding: 8px; + padding-right: 30px; } form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):focus + label, form.semanticForms select:focus + label, @@ -91,13 +100,42 @@ form.semanticForms select:not(:placeholder-shown) + label, form.semanticForms textarea:not(:placeholder-shown) + label { transform: translateY(-150%) scale(0.75); } +form.semanticForms input:placeholder-shown + label + .clear { + display: none; +} +form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]) { + height: 38px; +} form.semanticForms textarea { height: 100px; } form.semanticForms input[type=color] { padding: 4px !important; + padding-right: 30px !important; height: 38.5px; } +form.semanticForms .clear { + cursor: pointer; + appearance: none; + -webkit-appearance: none; + position: absolute; + top: 0; + right: 0; + margin-top: 8px; + background: none; + border: none; + border-radius: 50%; + width: 30px; + color: var(--placeholderColor); + display: flex; + align-items: center; + justify-content: center; +} +form.semanticForms .clear:hover, +form.semanticForms .clear:focus { + color: #333; + color: var(--subBorderColor); +} form.semanticForms input[type='submit'], form.semanticForms input[type='reset'], form.semanticForms input[type='image'], diff --git a/semanticForms.html b/semanticForms.html index a4dd2e2..4357466 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -246,6 +246,18 @@

Semantic Forms

+
+ Nested fieldset + +
+
+
+ +

Here is some subtext.

+
+
+
+ diff --git a/semanticForms.js b/semanticForms.js index 56c58e5..7a753c7 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -14,26 +14,7 @@ window.semanticForms = () => { // collect all form elements const inputs = Array.from(form.querySelectorAll('input, textarea, select')) - if (form.classList.contains('lowFlow')) { - for (const input of inputs) { - const dl = input.closest('dl') - const dt = input.closest('dd')?.previousElementSibling - const dd = input.closest('dd') - - if (dt && dt.nodeName === 'DT' && dd.nodeName === 'DD') { - // removes old div that a radio or checkbox may have been added to - if (dd.parentElement.nodeName === 'DIV') { - dd.parentElement.remove() - } - - const div = document.createElement('div') - div.append(dt, dd) - dl.append(div) - } - } - console.log('low flow') - continue - } + if (form.classList.contains('lowFlow')) continue const clearfieldHorizontalOffset = parseInt(form.getAttribute('data-clearfield-horizontal-offset')) || 21 const clearfieldVerticalOffset = parseInt(form.getAttribute('data-clearfield-vertical-offset')) || 5 @@ -102,7 +83,24 @@ window.semanticForms = () => { if (type !== 'checkbox' && type !== 'radio') { const div = document.createElement('div') - div.append(label.closest('dt'), input.closest('dd')) + const dt = label.closest('dt') + const dd = input.closest('dd') + + if (input.nodeName !== 'SELECT' && type !== 'range') { + const clearBtn = document.createElement('button') + clearBtn.type = 'button' + clearBtn.ariaLabel = 'Clear input' + clearBtn.innerHTML = '' + clearBtn.classList.add('clear') + clearBtn.addEventListener('click', () => { + input.value = '' + input.focus() + }) + + insertAfter(clearBtn, dd.querySelector('label')) + } + + div.append(dt, dd) dl.append(div) } diff --git a/semanticForms.less b/semanticForms.less index 81d42b1..a7b60ce 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -64,6 +64,16 @@ form.semanticForms { } } + &.lowFlow { + fieldset { + dl { + display: flex; + flex-direction: column; + gap: 5px; + } + } + } + menu { display: flex; justify-content: space-between; @@ -86,6 +96,10 @@ form.semanticForms { padding-left: 10px; } + dd { + position: relative; + } + // style all input types input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), select, @@ -97,6 +111,7 @@ form.semanticForms { border-radius: 5px; font-size: 16px; padding: 8px; + padding-right: 30px; &:focus + label, &:not(:placeholder-shown) + label { @@ -104,6 +119,14 @@ form.semanticForms { } } + input:placeholder-shown + label + .clear { + display: none; + } + + input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]) { + height: 38px; + } + textarea { height: 100px; } @@ -111,9 +134,35 @@ form.semanticForms { // specific styling for color input[type=color] { padding: 4px !important; + padding-right: 30px !important; height: 38.5px; } + .clear { + cursor: pointer; + appearance: none; + -webkit-appearance: none; + position: absolute; + // todo: we need to account for
's that are taller than just a single input + top: 0; + right: 0; + margin-top: 8px; + background: none; + border: none; + border-radius: 50%; + width: 30px; + color: var(--placeholderColor); + display: flex; + align-items: center; + justify-content: center; + + &:hover, + &:focus { + color: #333; + color: var(--subBorderColor); + } + } + // button styling input[type='submit'], input[type='reset'], From 0a9466610f6f35074d718da171b25170d185b9a7 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Thu, 22 Aug 2024 09:27:27 -0400 Subject: [PATCH 05/60] update scrollbars --- semanticForms.css | 32 ++++++++++++++++++++---- semanticForms.js | 14 +++++++++++ semanticForms.less | 61 +++++++++++++++++++++++++++++++++------------- 3 files changed, 85 insertions(+), 22 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index b64cf61..a9b7528 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -6,6 +6,7 @@ form.semanticForms.light { --borderColor: #c0c0c0; --subBorderColor: #c0c0c0; --placeholderColor: #aaa; + --scrollbarColor: #c0c0c0; } form.semanticForms.dark { --formBackgroundColor: #555; @@ -15,6 +16,7 @@ form.semanticForms.dark { --borderColor: #555; --subBorderColor: #3f3f3f; --placeholderColor: #aaa; + --scrollbarColor: #373737; } form.semanticForms * { box-sizing: border-box; @@ -44,7 +46,7 @@ form.semanticForms fieldset dl { grid-template-columns: 1fr 1fr; } } -@media screen and (max-width: 450px) { +@media screen and (max-width: 528px) { form.semanticForms fieldset dl { grid-template-columns: 1fr; } @@ -89,7 +91,7 @@ form.semanticForms textarea { width: 100%; border-radius: 5px; font-size: 16px; - padding: 8px; + padding: 6px; padding-right: 30px; } form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):focus + label, @@ -100,15 +102,36 @@ form.semanticForms select:not(:placeholder-shown) + label, form.semanticForms textarea:not(:placeholder-shown) + label { transform: translateY(-150%) scale(0.75); } -form.semanticForms input:placeholder-shown + label + .clear { +form.semanticForms input:placeholder-shown + label + .clear, +form.semanticForms textarea:placeholder-shown + label + .clear { display: none; } form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]) { height: 38px; } form.semanticForms textarea { + min-width: 100%; + width: 100%; + min-height: 38px; height: 100px; } +@supports (scrollbar-color: auto) { + form.semanticForms textarea { + scrollbar-color: var(--scrollbarColor) var(--formBackgroundColor); + } +} +@supports selector(::-webkit-scrollbar) { + form.semanticForms textarea::-webkit-scrollbar { + background-color: transparent; + width: 10px; + padding: 4px; + } + form.semanticForms textarea::-webkit-scrollbar-thumb { + cursor: pointer; + background: var(--scrollbarColor); + border-radius: 8px; + } +} form.semanticForms input[type=color] { padding: 4px !important; padding-right: 30px !important; @@ -121,11 +144,10 @@ form.semanticForms .clear { position: absolute; top: 0; right: 0; - margin-top: 8px; + margin: 8px 6px; background: none; border: none; border-radius: 50%; - width: 30px; color: var(--placeholderColor); display: flex; align-items: center; diff --git a/semanticForms.js b/semanticForms.js index 7a753c7..4ac9906 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -134,6 +134,20 @@ window.semanticForms = () => { } } }) + + // add listener to shift clear button when scrollbar present + for (const textarea of document.querySelectorAll('textarea')) { + // shifts the close button to the right if a scrollbar is present + const shiftCloseBtn = () => { + const clearBtn = textarea.parentElement.querySelector('button.clear') + textarea.clientHeight < textarea.scrollHeight + ? clearBtn.style.marginRight = '15px' + : clearBtn.style.marginRight = '' + } + + textarea.addEventListener('input', shiftCloseBtn) + textarea.addEventListener('mouseup', shiftCloseBtn) + } } } } diff --git a/semanticForms.less b/semanticForms.less index a7b60ce..0349d62 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -7,6 +7,7 @@ form.semanticForms.light { --borderColor: #c0c0c0; --subBorderColor: #c0c0c0; --placeholderColor: #aaa; + --scrollbarColor: #c0c0c0; } form.semanticForms.dark { @@ -17,6 +18,7 @@ form.semanticForms.dark { --borderColor: #555; --subBorderColor: #3f3f3f; --placeholderColor: #aaa; + --scrollbarColor: #373737; } // global override @@ -48,7 +50,7 @@ form.semanticForms { grid-template-columns: 1fr 1fr; } - @media screen and (max-width: 450px) { + @media screen and (max-width: 528px) { grid-template-columns: 1fr; } @@ -110,16 +112,17 @@ form.semanticForms { width: 100%; border-radius: 5px; font-size: 16px; - padding: 8px; + padding: 6px; padding-right: 30px; - &:focus + label, - &:not(:placeholder-shown) + label { + &:focus+label, + &:not(:placeholder-shown)+label { transform: translateY(-150%) scale(0.75); } } - input:placeholder-shown + label + .clear { + input:placeholder-shown+label+.clear, + textarea:placeholder-shown+label+.clear { display: none; } @@ -128,9 +131,32 @@ form.semanticForms { } textarea { + min-width: 100%; + width: 100%; + min-height: 38px; height: 100px; } + @supports (scrollbar-color: auto) { + textarea { + scrollbar-color: var(--scrollbarColor) var(--formBackgroundColor); + } + } + + @supports selector(::-webkit-scrollbar) { + textarea::-webkit-scrollbar { + background-color: transparent; + width: 10px; + padding: 4px; + } + + textarea::-webkit-scrollbar-thumb { + cursor: pointer; + background: var(--scrollbarColor); + border-radius: 8px; + } + } + // specific styling for color input[type=color] { padding: 4px !important; @@ -143,14 +169,12 @@ form.semanticForms { appearance: none; -webkit-appearance: none; position: absolute; - // todo: we need to account for
's that are taller than just a single input top: 0; right: 0; - margin-top: 8px; + margin: 8px 6px; background: none; border: none; border-radius: 50%; - width: 30px; color: var(--placeholderColor); display: flex; align-items: center; @@ -185,21 +209,22 @@ form.semanticForms { // } // style placeholders - input, textarea { + input, + textarea { &::placeholder { color: var(--placeholderColor); opacity: 1; } } - input:not(:placeholder-shown) + label, - input:focus + label, - textarea:not(:placeholder-shown) + label, - textarea:focus + label, - select + label.floatLabelFormAnimatedLabel, + input:not(:placeholder-shown)+label, + input:focus+label, + textarea:not(:placeholder-shown)+label, + textarea:focus+label, + select+label.floatLabelFormAnimatedLabel, .checkboxes label.floatLabelFormAnimatedLabel, .radios label.floatLabelFormAnimatedLabel, - dt > label { + dt>label { color: var(--formTextColor); } @@ -209,7 +234,7 @@ form.semanticForms { position: relative; dd:not(.singleCheckbox) { - > label { + >label { position: absolute; transform-origin: left center; pointer-events: none; @@ -222,7 +247,9 @@ form.semanticForms { text-overflow: ellipsis; } - input, textarea { + input, + textarea { + // hide placeholder content until input is focused &::placeholder { opacity: 0; From d087a79d6a989993a8d62e7911818c893985c14c Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Thu, 22 Aug 2024 09:36:03 -0400 Subject: [PATCH 06/60] styling for selects --- semanticForms.css | 9 +++++++++ semanticForms.js | 8 ++++---- semanticForms.less | 12 +++++++++--- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index a9b7528..47bb0ba 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -171,6 +171,15 @@ form.semanticForms button { form.semanticForms label { color: var(--placeholderColor); } +form.semanticForms select { + background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + background-size: 14px; + background-position: calc(100% - 8px) 12px; + background-repeat: no-repeat; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} form.semanticForms input::placeholder, form.semanticForms textarea::placeholder { color: var(--placeholderColor); diff --git a/semanticForms.js b/semanticForms.js index 4ac9906..dfdeb1b 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -139,10 +139,10 @@ window.semanticForms = () => { for (const textarea of document.querySelectorAll('textarea')) { // shifts the close button to the right if a scrollbar is present const shiftCloseBtn = () => { - const clearBtn = textarea.parentElement.querySelector('button.clear') - textarea.clientHeight < textarea.scrollHeight - ? clearBtn.style.marginRight = '15px' - : clearBtn.style.marginRight = '' + const clearBtn = textarea.parentElement?.querySelector('button.clear') + if (clearBtn) { + clearBtn.style.marginRight = textarea.clientHeight < textarea.scrollHeight ? '15px' : '' + } } textarea.addEventListener('input', shiftCloseBtn) diff --git a/semanticForms.less b/semanticForms.less index 0349d62..d9f94d6 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -204,9 +204,15 @@ form.semanticForms { color: var(--placeholderColor); } - // select { - // background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - // } + select { + background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + background-size: 14px; + background-position: calc(100% - 8px) 12px; + background-repeat: no-repeat; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + } // style placeholders input, From bfb87643356f9d4a5be4c47331c67967e202055a Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Fri, 23 Aug 2024 12:50:08 -0400 Subject: [PATCH 07/60] save progress --- semanticForms copy.less | 136 ++++++++++++++++++++-------------------- semanticForms.css | 95 ++++++++++++++++++++-------- semanticForms.html | 5 +- semanticForms.js | 2 +- semanticForms.less | 110 ++++++++++++++++++++++---------- 5 files changed, 219 insertions(+), 129 deletions(-) diff --git a/semanticForms copy.less b/semanticForms copy.less index 681a9a0..d2b49fd 100644 --- a/semanticForms copy.less +++ b/semanticForms copy.less @@ -115,87 +115,87 @@ form.semanticForms { // #region clear fields and custom select box design - input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), - textarea { - background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23000' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); - background-size: 12px; - background-repeat: no-repeat; - } + // input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), + // textarea { + // background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23000' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); + // background-size: 12px; + // background-repeat: no-repeat; + // } - input:not([type=checkbox]):not([type=radio]) { - background-position: right -12px center; - } + // input:not([type=checkbox]):not([type=radio]) { + // background-position: right -12px center; + // } - textarea { - background-position: right -12px top 10px; - height: 100px; - } + // textarea { + // background-position: right -12px top 10px; + // height: 100px; + // } - select { - background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - background-size: 14px; - background-position: calc(99%) 16px; - background-repeat: no-repeat; - width: 292px; - height: 37px; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - } + // select { + // background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + // background-size: 14px; + // background-position: calc(99%) 16px; + // background-repeat: no-repeat; + // width: 292px; + // height: 37px; + // -webkit-appearance: none; + // -moz-appearance: none; + // appearance: none; + // } // #endregion // #region style placeholders - input::placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } + // input::placeholder { + // color: @lightPlaceholderColor; + // opacity: 1; + // } - textarea::placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } + // textarea::placeholder { + // color: @lightPlaceholderColor; + // opacity: 1; + // } - input:focus::placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } + // input:focus::placeholder { + // color: @lightPlaceholderColor; + // opacity: 1; + // } - input:focus::-moz-placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } + // input:focus::-moz-placeholder { + // color: @lightPlaceholderColor; + // opacity: 1; + // } - input:focus::-webkit-input-placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } + // input:focus::-webkit-input-placeholder { + // color: @lightPlaceholderColor; + // opacity: 1; + // } - input:focus:-ms-input-placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } + // input:focus:-ms-input-placeholder { + // color: @lightPlaceholderColor; + // opacity: 1; + // } - textarea:focus::placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } + // textarea:focus::placeholder { + // color: @lightPlaceholderColor; + // opacity: 1; + // } - textarea:focus::-moz-placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } + // textarea:focus::-moz-placeholder { + // color: @lightPlaceholderColor; + // opacity: 1; + // } - textarea:focus::-webkit-input-placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } + // textarea:focus::-webkit-input-placeholder { + // color: @lightPlaceholderColor; + // opacity: 1; + // } - textarea:focus:-ms-input-placeholder { - color: @lightPlaceholderColor; - opacity: 1; - } + // textarea:focus:-ms-input-placeholder { + // color: @lightPlaceholderColor; + // opacity: 1; + // } // #endregion @@ -239,10 +239,10 @@ form.semanticForms { // #region float label forms - label.floatLabelFormAnimatedLabel, input:not([type=checkbox]):not([type=radio]), select, textarea, section { - transition: color 0.2s, text-indent 0.2s, transform 0.2s, background-position 0.2s; - touch-action: manipulation; - } + // label.floatLabelFormAnimatedLabel, input:not([type=checkbox]):not([type=radio]), select, textarea, section { + // transition: color 0.2s, text-indent 0.2s, transform 0.2s, background-position 0.2s; + // touch-action: manipulation; + // } .floatLabelForm { margin: 0 auto; diff --git a/semanticForms.css b/semanticForms.css index 47bb0ba..9151fa6 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -1,3 +1,6 @@ +form.semanticForms { + --inputHeight: 38px; +} form.semanticForms.light { --formBackgroundColor: #fff; --formSubBackgroundColor: #f5f5f5; @@ -15,7 +18,7 @@ form.semanticForms.dark { --buttonBackgroundColor: #373737; --borderColor: #555; --subBorderColor: #3f3f3f; - --placeholderColor: #aaa; + --placeholderColor: #C9C9C9; --scrollbarColor: #373737; } form.semanticForms * { @@ -54,9 +57,6 @@ form.semanticForms fieldset dl { form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios).singleCheckbox label { margin-top: 10px; } -form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios).singleCheckbox input { - margin: 10px 10px 0 0; -} form.semanticForms.lowFlow fieldset dl { display: flex; flex-direction: column; @@ -73,11 +73,20 @@ form.semanticForms dt { form.semanticForms dt label[data-for="checkboxes"], form.semanticForms dt label[data-for="radios"] { position: absolute; - transform: translateY(-100%) scale(0.75); + transform: translateY(-100%) scale(0.8); } form.semanticForms .checkboxes ul, form.semanticForms .radios ul { padding-left: 10px; + display: flex; + flex-direction: column; + gap: 4px; +} +form.semanticForms input[type=checkbox], +form.semanticForms input[type=radio] { + margin-right: 10px; + padding: 8px; + transform: scale(1.5); } form.semanticForms dd { position: relative; @@ -93,6 +102,18 @@ form.semanticForms textarea { font-size: 16px; padding: 6px; padding-right: 30px; + touch-action: manipulation; +} +form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio])[disabled], +form.semanticForms select[disabled], +form.semanticForms textarea[disabled] { + cursor: not-allowed; + opacity: 0.5; +} +form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio])[disabled] + label, +form.semanticForms select[disabled] + label, +form.semanticForms textarea[disabled] + label { + filter: brightness(50%); } form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):focus + label, form.semanticForms select:focus + label, @@ -102,12 +123,13 @@ form.semanticForms select:not(:placeholder-shown) + label, form.semanticForms textarea:not(:placeholder-shown) + label { transform: translateY(-150%) scale(0.75); } -form.semanticForms input:placeholder-shown + label + .clear, -form.semanticForms textarea:placeholder-shown + label + .clear { - display: none; +form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), +form.semanticForms select { + height: var(--inputHeight); } -form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]) { - height: 38px; +form.semanticForms label { + color: var(--placeholderColor); + touch-action: manipulation; } form.semanticForms textarea { min-width: 100%; @@ -135,7 +157,17 @@ form.semanticForms textarea { form.semanticForms input[type=color] { padding: 4px !important; padding-right: 30px !important; - height: 38.5px; + height: var(--inputHeight); +} +form.semanticForms select { + cursor: pointer; + background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + background-size: 14px; + background-position: calc(100% - 8px) 16px; + background-repeat: no-repeat; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; } form.semanticForms .clear { cursor: pointer; @@ -144,7 +176,7 @@ form.semanticForms .clear { position: absolute; top: 0; right: 0; - margin: 8px 6px; + margin: 6px; background: none; border: none; border-radius: 50%; @@ -158,27 +190,19 @@ form.semanticForms .clear:focus { color: #333; color: var(--subBorderColor); } +form.semanticForms input:placeholder-shown + label + .clear, +form.semanticForms textarea:placeholder-shown + label + .clear { + display: none; +} form.semanticForms input[type='submit'], form.semanticForms input[type='reset'], form.semanticForms input[type='image'], form.semanticForms button { background: var(--buttonBackgroundColor); - border-radius: 5px; - padding: 5px; color: var(--formTextColor); border: 2px var(--borderColor) solid; -} -form.semanticForms label { - color: var(--placeholderColor); -} -form.semanticForms select { - background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - background-size: 14px; - background-position: calc(100% - 8px) 12px; - background-repeat: no-repeat; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; + border-radius: 5px; + padding: 5px; } form.semanticForms input::placeholder, form.semanticForms textarea::placeholder { @@ -202,7 +226,7 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) > label { position: absolute; transform-origin: left center; pointer-events: none; - top: 8px; + top: 10px; left: 8px; transition: transform 250ms; cursor: text; @@ -246,3 +270,20 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input:focus:-ms-i form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea:focus:-ms-input-placeholder { opacity: 1; } +form.semanticForms .floatLabelForm input:-webkit-autofill, +form.semanticForms .floatLabelForm input:-webkit-autofill:hover, +form.semanticForms .floatLabelForm input:-webkit-autofill:focus, +form.semanticForms .floatLabelForm input:-webkit-autofill:active, +form.semanticForms .floatLabelForm textarea:-webkit-autofill, +form.semanticForms .floatLabelForm textarea:-webkit-autofill:hover, +form.semanticForms .floatLabelForm textarea:-webkit-autofill:focus, +form.semanticForms .floatLabelForm textarea:-webkit-autofill:active, +form.semanticForms .floatLabelForm select:-webkit-autofill, +form.semanticForms .floatLabelForm select:-webkit-autofill:hover, +form.semanticForms .floatLabelForm select:-webkit-autofill:focus, +form.semanticForms .floatLabelForm select:-webkit-autofill:active { + -webkit-box-shadow: 0 0 0 1000px var(--formBackgroundColor) inset; + transition: background-color 5000s ease-in-out 0s, color 5000s ease-in-out 0s; + transition-delay: 5000s; + transition-property: background-color, color; +} diff --git a/semanticForms.html b/semanticForms.html index 4357466..2cccbac 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -59,6 +59,9 @@

Semantic Forms

+
+
+
+
  • diff --git a/semanticForms.js b/semanticForms.js index dfdeb1b..24e3001 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -90,7 +90,7 @@ window.semanticForms = () => { const clearBtn = document.createElement('button') clearBtn.type = 'button' clearBtn.ariaLabel = 'Clear input' - clearBtn.innerHTML = '' + clearBtn.innerHTML = '' clearBtn.classList.add('clear') clearBtn.addEventListener('click', () => { input.value = '' diff --git a/semanticForms.less b/semanticForms.less index d9f94d6..68810f4 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -1,4 +1,8 @@ // setup global colors +form.semanticForms { + --inputHeight: 38px; +} + form.semanticForms.light { --formBackgroundColor: #fff; --formSubBackgroundColor: #f5f5f5; @@ -17,7 +21,7 @@ form.semanticForms.dark { --buttonBackgroundColor: #373737; --borderColor: #555; --subBorderColor: #3f3f3f; - --placeholderColor: #aaa; + --placeholderColor: #C9C9C9; --scrollbarColor: #373737; } @@ -58,14 +62,11 @@ form.semanticForms { label { margin-top: 10px; } - - input { - margin: 10px 10px 0 0; - } } } } + // low flow specific styling &.lowFlow { fieldset { dl { @@ -89,13 +90,23 @@ form.semanticForms { label[data-for="checkboxes"], label[data-for="radios"] { position: absolute; - transform: translateY(-100%) scale(0.75); + transform: translateY(-100%) scale(0.8); } } .checkboxes ul, .radios ul { padding-left: 10px; + display: flex; + flex-direction: column; + gap: 4px; + } + + input[type=checkbox], + input[type=radio] { + margin-right: 10px; + padding: 8px; + transform: scale(1.5); } dd { @@ -114,20 +125,31 @@ form.semanticForms { font-size: 16px; padding: 6px; padding-right: 30px; + touch-action: manipulation; + + &[disabled] { + cursor: not-allowed; + opacity: 0.5; + + + label { + filter: brightness(50%); + } + } - &:focus+label, + &:focus + label, &:not(:placeholder-shown)+label { transform: translateY(-150%) scale(0.75); } } - input:placeholder-shown+label+.clear, - textarea:placeholder-shown+label+.clear { - display: none; + input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), + select { + height: var(--inputHeight); } - input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]) { - height: 38px; + label { + color: var(--placeholderColor); + touch-action: manipulation; } textarea { @@ -137,6 +159,7 @@ form.semanticForms { height: 100px; } + // update for scrollbars @supports (scrollbar-color: auto) { textarea { scrollbar-color: var(--scrollbarColor) var(--formBackgroundColor); @@ -157,13 +180,26 @@ form.semanticForms { } } - // specific styling for color + // specific styling for color input input[type=color] { padding: 4px !important; padding-right: 30px !important; - height: 38.5px; + height: var(--inputHeight); } + // custom dropdown graphic on select element + select { + cursor: pointer; + background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + background-size: 14px; + background-position: calc(100% - 8px) 16px; + background-repeat: no-repeat; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + } + + // "x" button that appears when a value is entered .clear { cursor: pointer; appearance: none; @@ -171,7 +207,7 @@ form.semanticForms { position: absolute; top: 0; right: 0; - margin: 8px 6px; + margin: 6px; background: none; border: none; border-radius: 50%; @@ -187,6 +223,12 @@ form.semanticForms { } } + // hide clear button while placeholder text is visible + input:placeholder-shown + label + .clear, + textarea:placeholder-shown + label + .clear { + display: none; + } + // button styling input[type='submit'], input[type='reset'], @@ -194,24 +236,9 @@ form.semanticForms { button { background: var(--buttonBackgroundColor); color: var(--formTextColor); + border: 2px var(--borderColor) solid; border-radius: 5px; padding: 5px; - color: var(--formTextColor); - border: 2px var(--borderColor) solid; - } - - label { - color: var(--placeholderColor); - } - - select { - background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - background-size: 14px; - background-position: calc(100% - 8px) 12px; - background-repeat: no-repeat; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; } // style placeholders @@ -244,7 +271,7 @@ form.semanticForms { position: absolute; transform-origin: left center; pointer-events: none; - top: 8px; + top: 10px; left: 8px; transition: transform 250ms; cursor: text; @@ -298,5 +325,24 @@ form.semanticForms { } } } + + // disable autofill yellow + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + input:-webkit-autofill:active, + textarea:-webkit-autofill, + textarea:-webkit-autofill:hover, + textarea:-webkit-autofill:focus, + textarea:-webkit-autofill:active, + select:-webkit-autofill, + select:-webkit-autofill:hover, + select:-webkit-autofill:focus, + select:-webkit-autofill:active { + -webkit-box-shadow: 0 0 0 1000px var(--formBackgroundColor) inset; + transition: background-color 5000s ease-in-out 0s, color 5000s ease-in-out 0s; + transition-delay: 5000s; + transition-property: background-color, color; + } } } \ No newline at end of file From 5669b220c94c838961c1c8851dd2d616e8807f8e Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Mon, 26 Aug 2024 12:20:18 -0400 Subject: [PATCH 08/60] various tweaks --- semanticForms.css | 83 ++++++++++++++++++---------------------------- semanticForms.js | 9 +++-- semanticForms.less | 80 ++++++++++++++++++++++---------------------- 3 files changed, 78 insertions(+), 94 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index 9151fa6..486918f 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -1,7 +1,5 @@ form.semanticForms { --inputHeight: 38px; -} -form.semanticForms.light { --formBackgroundColor: #fff; --formSubBackgroundColor: #f5f5f5; --formTextColor: #000; @@ -25,7 +23,6 @@ form.semanticForms * { box-sizing: border-box; margin: 0; padding: 0; - list-style-type: none; font-family: sans-serif; } form.semanticForms { @@ -35,37 +32,35 @@ form.semanticForms { form.semanticForms fieldset { border-radius: 10px; padding: 20px 10px; - margin-bottom: 25px; + margin-bottom: 15px; background: var(--formSubBackgroundColor); border: 1px var(--subBorderColor) solid; } form.semanticForms fieldset dl { display: grid; - grid-template-columns: 1fr 1fr 1fr; - gap: 25px; -} -@media screen and (max-width: 768px) { - form.semanticForms fieldset dl { - grid-template-columns: 1fr 1fr; - } + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 10px; + margin-bottom: 10px; } -@media screen and (max-width: 528px) { - form.semanticForms fieldset dl { - grid-template-columns: 1fr; - } +form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios) { + display: flex; + gap: 10px; + margin-left: 5px; } -form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios).singleCheckbox label { - margin-top: 10px; +form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios) label { + cursor: pointer; } form.semanticForms.lowFlow fieldset dl { display: flex; flex-direction: column; gap: 5px; } -form.semanticForms menu { +form.semanticForms menu, +form.semanticForms ul { display: flex; justify-content: space-between; padding: 5px; + list-style-type: none; } form.semanticForms dt { position: relative; @@ -84,8 +79,6 @@ form.semanticForms .radios ul { } form.semanticForms input[type=checkbox], form.semanticForms input[type=radio] { - margin-right: 10px; - padding: 8px; transform: scale(1.5); } form.semanticForms dd { @@ -142,18 +135,6 @@ form.semanticForms textarea { scrollbar-color: var(--scrollbarColor) var(--formBackgroundColor); } } -@supports selector(::-webkit-scrollbar) { - form.semanticForms textarea::-webkit-scrollbar { - background-color: transparent; - width: 10px; - padding: 4px; - } - form.semanticForms textarea::-webkit-scrollbar-thumb { - cursor: pointer; - background: var(--scrollbarColor); - border-radius: 8px; - } -} form.semanticForms input[type=color] { padding: 4px !important; padding-right: 30px !important; @@ -198,9 +179,10 @@ form.semanticForms input[type='submit'], form.semanticForms input[type='reset'], form.semanticForms input[type='image'], form.semanticForms button { + cursor: pointer; background: var(--buttonBackgroundColor); color: var(--formTextColor); - border: 2px var(--borderColor) solid; + border: 1px var(--borderColor) solid; border-radius: 5px; padding: 5px; } @@ -221,8 +203,9 @@ form.semanticForms dt > label { } form.semanticForms .floatLabelForm div { position: relative; + margin-top: 10px; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) > label { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) label { position: absolute; transform-origin: left center; pointer-events: none; @@ -234,40 +217,40 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) > label { overflow: hidden; text-overflow: ellipsis; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input::placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea::placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input::placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea::placeholder { opacity: 0; transition: inherit; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input::-moz-placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea::-moz-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input::-moz-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea::-moz-placeholder { opacity: 0; transition: inherit; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input::-webkit-input-placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea::-webkit-input-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input::-webkit-input-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea::-webkit-input-placeholder { opacity: 0; transition: inherit; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input:-ms-input-placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea:-ms-input-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input:-ms-input-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea:-ms-input-placeholder { opacity: 0; transition: inherit; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input:focus::placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea:focus::placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input:focus::placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea:focus::placeholder { opacity: 1; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input:focus::-moz-placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea:focus::-moz-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input:focus::-moz-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea:focus::-moz-placeholder { opacity: 1; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input:focus::-webkit-input-placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea:focus::-webkit-input-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input:focus::-webkit-input-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea:focus::-webkit-input-placeholder { opacity: 1; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) input:focus:-ms-input-placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox) textarea:focus:-ms-input-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input:focus:-ms-input-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea:focus:-ms-input-placeholder { opacity: 1; } form.semanticForms .floatLabelForm input:-webkit-autofill, diff --git a/semanticForms.js b/semanticForms.js index 24e3001..13a9a1b 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -26,8 +26,10 @@ window.semanticForms = () => { const type = input.getAttribute('type') if (nodeNameLookup.includes(input.nodeName) || typeLookup.includes(type)) { - const dl = input.closest('dl') - dl.classList.toggle('floatLabelForm', true) + let dl = input.parentNode + while (dl && dl.nodeName !== 'DL') dl = dl.parentNode + if (!dl) continue + if (!dl.classList.contains('floatLabelForm')) dl.classList.add('floatLabelForm') let label @@ -41,7 +43,8 @@ window.semanticForms = () => { // checkboxes and radios if (type === 'checkbox' || type === 'radio') { - const dd = input.closest('dd') + let dd = input.parentNode + while (dd && dd.nodeName !== 'DD') dd = dd.parentNode if (dd.firstChild.nodeName !== 'LABEL') { const newLabel = document.createElement('label') newLabel.className = 'floatLabelFormAnimatedLabel' diff --git a/semanticForms.less b/semanticForms.less index 68810f4..4c40e77 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -1,9 +1,6 @@ // setup global colors form.semanticForms { --inputHeight: 38px; -} - -form.semanticForms.light { --formBackgroundColor: #fff; --formSubBackgroundColor: #f5f5f5; --formTextColor: #000; @@ -30,7 +27,6 @@ form.semanticForms * { box-sizing: border-box; margin: 0; padding: 0; - list-style-type: none; font-family: sans-serif; } @@ -41,26 +37,23 @@ form.semanticForms { fieldset { border-radius: 10px; padding: 20px 10px; - margin-bottom: 25px; + margin-bottom: 15px; background: var(--formSubBackgroundColor); border: 1px var(--subBorderColor) solid; dl { display: grid; - grid-template-columns: 1fr 1fr 1fr; - gap: 25px; - - @media screen and (max-width: 768px) { - grid-template-columns: 1fr 1fr; - } + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 10px; + margin-bottom: 10px; - @media screen and (max-width: 528px) { - grid-template-columns: 1fr; - } + dd:not(.checkboxes):not(.radios) { + display: flex; + gap: 10px; + margin-left: 5px; - dd:not(.checkboxes):not(.radios).singleCheckbox { label { - margin-top: 10px; + cursor: pointer; } } } @@ -77,10 +70,11 @@ form.semanticForms { } } - menu { + menu, ul { display: flex; justify-content: space-between; padding: 5px; + list-style-type: none; } // adjust checkbox and radios labels @@ -104,8 +98,6 @@ form.semanticForms { input[type=checkbox], input[type=radio] { - margin-right: 10px; - padding: 8px; transform: scale(1.5); } @@ -166,19 +158,19 @@ form.semanticForms { } } - @supports selector(::-webkit-scrollbar) { - textarea::-webkit-scrollbar { - background-color: transparent; - width: 10px; - padding: 4px; - } + // @supports selector(::-webkit-scrollbar) { + // textarea::-webkit-scrollbar { + // background-color: transparent; + // width: 10px; + // padding: 4px; + // } - textarea::-webkit-scrollbar-thumb { - cursor: pointer; - background: var(--scrollbarColor); - border-radius: 8px; - } - } + // textarea::-webkit-scrollbar-thumb { + // cursor: pointer; + // background: var(--scrollbarColor); + // border-radius: 8px; + // } + // } // specific styling for color input input[type=color] { @@ -234,9 +226,10 @@ form.semanticForms { input[type='reset'], input[type='image'], button { + cursor: pointer; background: var(--buttonBackgroundColor); color: var(--formTextColor); - border: 2px var(--borderColor) solid; + border: 1px var(--borderColor) solid; border-radius: 5px; padding: 5px; } @@ -250,14 +243,14 @@ form.semanticForms { } } - input:not(:placeholder-shown)+label, - input:focus+label, - textarea:not(:placeholder-shown)+label, - textarea:focus+label, - select+label.floatLabelFormAnimatedLabel, + input:not(:placeholder-shown) + label, + input:focus + label, + textarea:not(:placeholder-shown) + label, + textarea:focus + label, + select + label.floatLabelFormAnimatedLabel, .checkboxes label.floatLabelFormAnimatedLabel, .radios label.floatLabelFormAnimatedLabel, - dt>label { + dt > label { color: var(--formTextColor); } @@ -265,9 +258,15 @@ form.semanticForms { .floatLabelForm { div { position: relative; + margin-top: 10px; + + dd.checkboxes, + dd.radios { - dd:not(.singleCheckbox) { - >label { + } + + dd:not(.singleCheckbox):not(.checkboxes):not(.radios) { + label { position: absolute; transform-origin: left center; pointer-events: none; @@ -282,7 +281,6 @@ form.semanticForms { input, textarea { - // hide placeholder content until input is focused &::placeholder { opacity: 0; From 3e8772e1cdbf5f4b8dc771730a39a56416cba6e3 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Thu, 29 Aug 2024 10:37:01 -0400 Subject: [PATCH 09/60] tweaks to spacing, remove watch package --- package-lock.json | 35 +-------------- package.json | 3 +- semanticForms.css | 70 ++++++++++++++++++----------- semanticForms.js | 73 ++++++++---------------------- semanticForms.less | 110 +++++++++++++++++++++++---------------------- 5 files changed, 122 insertions(+), 169 deletions(-) diff --git a/package-lock.json b/package-lock.json index a5c7c3e..cbcfb10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,6 @@ "name": "semantic-forms", "version": "3.2.1", "license": "CC-BY-4.0", - "dependencies": { - "watch": "^1.0.2" - }, "devDependencies": { "eslint": "9.9.1", "eslint-plugin-html": "8.1.1", @@ -1293,15 +1290,6 @@ "node": ">=0.10.0" } }, - "node_modules/exec-sh": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", - "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", - "license": "MIT", - "dependencies": { - "merge": "^1.2.0" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2305,12 +2293,6 @@ "node": ">=6" } }, - "node_modules/merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", - "license": "MIT" - }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -2340,6 +2322,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3759,22 +3742,6 @@ "node": ">=0.10.48" } }, - "node_modules/watch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", - "integrity": "sha512-1u+Z5n9Jc1E2c7qDO8SinPoZuHj7FgbgU1olSFoyaklduDvvtX7GMMtlE6OC9FTXq4KvNAOfj6Zu4vI1e9bAKA==", - "license": "Apache-2.0", - "dependencies": { - "exec-sh": "^0.2.0", - "minimist": "^1.2.0" - }, - "bin": { - "watch": "cli.js" - }, - "engines": { - "node": ">=0.1.95" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index bf73bd5..27b93e5 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,7 @@ "coverage": "echo \"TODO: test coverage\"", "lint": "standard && standard --plugin html *.html", "lint-fix": "standard --fix && standard --plugin html *.html --fix", - "build": "lessc semanticForms.less semanticForms.css", - "watch": "watch 'npm run build' ./" + "build": "lessc semanticForms.less semanticForms.css" }, "repository": { "type": "git", diff --git a/semanticForms.css b/semanticForms.css index 486918f..5745e6a 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -8,16 +8,18 @@ form.semanticForms { --subBorderColor: #c0c0c0; --placeholderColor: #aaa; --scrollbarColor: #c0c0c0; + --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); } form.semanticForms.dark { --formBackgroundColor: #555; --formSubBackgroundColor: #2f2f2f; --formTextColor: #fff; - --buttonBackgroundColor: #373737; - --borderColor: #555; + --buttonBackgroundColor: #454545; + --borderColor: #656565; --subBorderColor: #3f3f3f; --placeholderColor: #C9C9C9; --scrollbarColor: #373737; + --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); } form.semanticForms * { box-sizing: border-box; @@ -38,23 +40,21 @@ form.semanticForms fieldset { } form.semanticForms fieldset dl { display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 10px; margin-bottom: 10px; } form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios) { display: flex; gap: 10px; - margin-left: 5px; + max-width: 500px; +} +form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios):not(.singleCheckbox) { + flex-direction: column; } form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios) label { cursor: pointer; } -form.semanticForms.lowFlow fieldset dl { - display: flex; - flex-direction: column; - gap: 5px; -} form.semanticForms menu, form.semanticForms ul { display: flex; @@ -69,18 +69,16 @@ form.semanticForms dt label[data-for="checkboxes"], form.semanticForms dt label[data-for="radios"] { position: absolute; transform: translateY(-100%) scale(0.8); + top: 10px; } form.semanticForms .checkboxes ul, form.semanticForms .radios ul { padding-left: 10px; + margin-top: 5px; display: flex; flex-direction: column; gap: 4px; } -form.semanticForms input[type=checkbox], -form.semanticForms input[type=radio] { - transform: scale(1.5); -} form.semanticForms dd { position: relative; } @@ -93,9 +91,13 @@ form.semanticForms textarea { width: 100%; border-radius: 5px; font-size: 16px; + touch-action: manipulation; +} +form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type="range"]), +form.semanticForms select:not([type="range"]), +form.semanticForms textarea:not([type="range"]) { padding: 6px; padding-right: 30px; - touch-action: manipulation; } form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio])[disabled], form.semanticForms select[disabled], @@ -142,7 +144,7 @@ form.semanticForms input[type=color] { } form.semanticForms select { cursor: pointer; - background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + background-image: var(--selectIcon); background-size: 14px; background-position: calc(100% - 8px) 16px; background-repeat: no-repeat; @@ -155,12 +157,13 @@ form.semanticForms .clear { appearance: none; -webkit-appearance: none; position: absolute; - top: 0; + top: 10px; + bottom: 0; right: 0; - margin: 6px; + margin: auto 6px; + padding: 5px; background: none; border: none; - border-radius: 50%; color: var(--placeholderColor); display: flex; align-items: center; @@ -168,23 +171,27 @@ form.semanticForms .clear { } form.semanticForms .clear:hover, form.semanticForms .clear:focus { - color: #333; - color: var(--subBorderColor); + filter: brightness(0.8); +} +form.semanticForms textarea + label + .clear { + margin: 6px; + bottom: auto; } form.semanticForms input:placeholder-shown + label + .clear, -form.semanticForms textarea:placeholder-shown + label + .clear { +form.semanticForms textarea:placeholder-shown + label + .clear, +form.semanticForms input[type=file] + label + .clear { display: none; } form.semanticForms input[type='submit'], form.semanticForms input[type='reset'], form.semanticForms input[type='image'], -form.semanticForms button { +form.semanticForms button:not(.clear) { cursor: pointer; background: var(--buttonBackgroundColor); color: var(--formTextColor); border: 1px var(--borderColor) solid; border-radius: 5px; - padding: 5px; + padding: 10px; } form.semanticForms input::placeholder, form.semanticForms textarea::placeholder { @@ -203,13 +210,12 @@ form.semanticForms dt > label { } form.semanticForms .floatLabelForm div { position: relative; - margin-top: 10px; } form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) label { position: absolute; transform-origin: left center; pointer-events: none; - top: 10px; + top: 20px; left: 8px; transition: transform 250ms; cursor: text; @@ -217,6 +223,11 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes): overflow: hidden; text-overflow: ellipsis; } +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) select { + margin-top: 10px; +} form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input::placeholder, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea::placeholder { opacity: 0; @@ -270,3 +281,12 @@ form.semanticForms .floatLabelForm select:-webkit-autofill:active { transition-delay: 5000s; transition-property: background-color, color; } +form.semanticForms.lowFlow fieldset dl { + display: flex; + flex-direction: column; + gap: 5px; +} +form.semanticForms.lowFlow fieldset dd { + flex-direction: row !important; + margin-bottom: 10px; +} diff --git a/semanticForms.js b/semanticForms.js index 13a9a1b..250e0ee 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -16,9 +16,6 @@ window.semanticForms = () => { if (form.classList.contains('lowFlow')) continue - const clearfieldHorizontalOffset = parseInt(form.getAttribute('data-clearfield-horizontal-offset')) || 21 - const clearfieldVerticalOffset = parseInt(form.getAttribute('data-clearfield-vertical-offset')) || 5 - for (const input of inputs) { // check if input has already been formatted if (input.classList.contains('semanticform') || !input.id) continue @@ -79,12 +76,11 @@ window.semanticForms = () => { } // standard inputs - if (input.nodeName !== 'SELECT' && type !== 'checkbox' && type !== 'radio') { - if (!input.getAttribute('placeholder')) input.setAttribute('placeholder', ' ') - inputHandler(input) // force x to appear on inputs with prefilled value - } - if (type !== 'checkbox' && type !== 'radio') { + if (!input.getAttribute('placeholder')) { + input.setAttribute('placeholder', ' ') + } + const div = document.createElement('div') const dt = label.closest('dt') const dd = input.closest('dd') @@ -93,7 +89,7 @@ window.semanticForms = () => { const clearBtn = document.createElement('button') clearBtn.type = 'button' clearBtn.ariaLabel = 'Clear input' - clearBtn.innerHTML = '' + clearBtn.innerHTML = '' clearBtn.classList.add('clear') clearBtn.addEventListener('click', () => { input.value = '' @@ -105,38 +101,21 @@ window.semanticForms = () => { div.append(dt, dd) dl.append(div) + if (dt.style.display === 'none' && dd.style.display === 'none') { + div.style.display = 'none' + } } - input.addEventListener('input', inputHandler) - input.addEventListener('mousemove', event => { - const el = event.target - - if (el.nodeName === 'TEXTAREA' || typeLookup.includes(el.getAttribute('type'))) { - inputHandler(event) - if (el.offsetWidth - clearfieldHorizontalOffset < event.clientX - el.getBoundingClientRect().left && clearfieldHorizontalOffset + clearfieldVerticalOffset > event.clientY - el.getBoundingClientRect().top - ) { - if (!el.classList.contains('onX')) { - el.classList.add('onX') - } - } else { - el.classList.remove('onX') - } - } - }) - input.addEventListener('click', event => { - const el = event.target - if (el.nodeName === 'TEXTAREA' || typeLookup.includes(el.getAttribute('type'))) { - if (el.offsetWidth - clearfieldHorizontalOffset < event.clientX - el.getBoundingClientRect().left && - clearfieldHorizontalOffset + clearfieldVerticalOffset > event.clientY - el.getBoundingClientRect().top - ) { - el.value = '' - el.dispatchEvent(new Event('input')) - el.form.dispatchEvent(new Event('input')) - el.classList.remove('x') - el.classList.remove('onX') - } - } - }) + // handle file input clear btn - cannot be handled with CSS + if (type === 'file') { + const clearBtn = input.parentElement.querySelector('.clear') + input.addEventListener('input', e => { + clearBtn.style.display = e.target.files.length ? 'flex' : 'none' + }) + clearBtn.addEventListener('click', () => { + clearBtn.style.display = 'none' + }) + } // add listener to shift clear button when scrollbar present for (const textarea of document.querySelectorAll('textarea')) { @@ -155,22 +134,6 @@ window.semanticForms = () => { } } - // handle keystrokes or other input - function inputHandler (event) { - const el = event.target || event - const nodeName = el.nodeName - const type = el.getAttribute('type') || nodeName === 'TEXTAREA' - if ((nodeName && type) && (nodeName === 'TEXTAREA' || typeLookup.includes(type))) { - if (el.value) { - if (!el.classList.contains('x')) { - el.classList.add('x') - } - } else { - el.classList.remove('x') - } - } - } - // utility method for inserting an element after another element function insertAfter (newNode, referenceNode) { if (referenceNode.nextSibling) referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling) diff --git a/semanticForms.less b/semanticForms.less index 4c40e77..1db4351 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -9,17 +9,19 @@ form.semanticForms { --subBorderColor: #c0c0c0; --placeholderColor: #aaa; --scrollbarColor: #c0c0c0; + --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); } form.semanticForms.dark { --formBackgroundColor: #555; --formSubBackgroundColor: #2f2f2f; --formTextColor: #fff; - --buttonBackgroundColor: #373737; - --borderColor: #555; + --buttonBackgroundColor: #454545; + --borderColor: #656565; --subBorderColor: #3f3f3f; --placeholderColor: #C9C9C9; --scrollbarColor: #373737; + --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); } // global override @@ -43,14 +45,18 @@ form.semanticForms { dl { display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); // allows grid items to automatically resize gap: 10px; margin-bottom: 10px; dd:not(.checkboxes):not(.radios) { display: flex; gap: 10px; - margin-left: 5px; + max-width: 500px; // prevents inputs from spanning entire width + + &:not(.singleCheckbox) { + flex-direction: column; + } label { cursor: pointer; @@ -59,17 +65,6 @@ form.semanticForms { } } - // low flow specific styling - &.lowFlow { - fieldset { - dl { - display: flex; - flex-direction: column; - gap: 5px; - } - } - } - menu, ul { display: flex; justify-content: space-between; @@ -85,22 +80,19 @@ form.semanticForms { label[data-for="radios"] { position: absolute; transform: translateY(-100%) scale(0.8); + top: 10px; } } .checkboxes ul, .radios ul { padding-left: 10px; + margin-top: 5px; display: flex; flex-direction: column; gap: 4px; } - input[type=checkbox], - input[type=radio] { - transform: scale(1.5); - } - dd { position: relative; } @@ -115,10 +107,13 @@ form.semanticForms { width: 100%; border-radius: 5px; font-size: 16px; - padding: 6px; - padding-right: 30px; touch-action: manipulation; + &:not([type="range"]) { + padding: 6px; + padding-right: 30px; + } + &[disabled] { cursor: not-allowed; opacity: 0.5; @@ -158,20 +153,6 @@ form.semanticForms { } } - // @supports selector(::-webkit-scrollbar) { - // textarea::-webkit-scrollbar { - // background-color: transparent; - // width: 10px; - // padding: 4px; - // } - - // textarea::-webkit-scrollbar-thumb { - // cursor: pointer; - // background: var(--scrollbarColor); - // border-radius: 8px; - // } - // } - // specific styling for color input input[type=color] { padding: 4px !important; @@ -182,7 +163,7 @@ form.semanticForms { // custom dropdown graphic on select element select { cursor: pointer; - background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + background-image: var(--selectIcon); background-size: 14px; background-position: calc(100% - 8px) 16px; background-repeat: no-repeat; @@ -192,17 +173,18 @@ form.semanticForms { } // "x" button that appears when a value is entered - .clear { + button.clear { cursor: pointer; appearance: none; -webkit-appearance: none; position: absolute; - top: 0; + top: 10px; // account for margin above each input + bottom: 0; right: 0; - margin: 6px; + margin: auto 6px; + padding: 5px; background: none; border: none; - border-radius: 50%; color: var(--placeholderColor); display: flex; align-items: center; @@ -210,14 +192,20 @@ form.semanticForms { &:hover, &:focus { - color: #333; - color: var(--subBorderColor); + filter: brightness(0.8); } } + // custom styling of clear button on textarea + textarea + label + .clear { + margin: 6px; + bottom: auto; + } + // hide clear button while placeholder text is visible input:placeholder-shown + label + .clear, - textarea:placeholder-shown + label + .clear { + textarea:placeholder-shown + label + .clear, + input[type=file] + label + .clear { display: none; } @@ -225,13 +213,13 @@ form.semanticForms { input[type='submit'], input[type='reset'], input[type='image'], - button { + button:not(.clear) { cursor: pointer; background: var(--buttonBackgroundColor); color: var(--formTextColor); border: 1px var(--borderColor) solid; border-radius: 5px; - padding: 5px; + padding: 10px; } // style placeholders @@ -258,19 +246,13 @@ form.semanticForms { .floatLabelForm { div { position: relative; - margin-top: 10px; - - dd.checkboxes, - dd.radios { - - } dd:not(.singleCheckbox):not(.checkboxes):not(.radios) { label { position: absolute; transform-origin: left center; pointer-events: none; - top: 10px; + top: 20px; left: 8px; transition: transform 250ms; cursor: text; @@ -279,6 +261,12 @@ form.semanticForms { text-overflow: ellipsis; } + input, + textarea, + select { + margin-top: 10px; + } + input, textarea { // hide placeholder content until input is focused @@ -343,4 +331,20 @@ form.semanticForms { transition-property: background-color, color; } } + + // low flow specific styling + &.lowFlow { + fieldset { + dl { + display: flex; + flex-direction: column; + gap: 5px; + } + + dd { + flex-direction: row !important; + margin-bottom: 10px; + } + } + } } \ No newline at end of file From 87a011a0aa20f1e18f5d781913a57e48281ddad1 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Sun, 1 Sep 2024 09:42:14 -0400 Subject: [PATCH 10/60] match styling to previous version --- CHANGELOG.md | 5 ++- semanticForms.css | 92 +++++++++++++++++++++++++++++++++------------- semanticForms.js | 20 +++++----- semanticForms.less | 91 +++++++++++++++++++++++++++++++-------------- 4 files changed, 143 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c63963c..57d33d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ## Next version -- Put your changes here... +- Rewrite of CSS, includes the following changes: + - Fieldset elements now utilize CSS grid to dynamically fill available space before wrapping to the next row. + - Input clear button is now a button element, allowing interaction via tab. + - Input clear button avoids overlap with scrollbars on textarea elements. ## 3.2.1 diff --git a/semanticForms.css b/semanticForms.css index 5745e6a..b61062f 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -1,5 +1,6 @@ form.semanticForms { --inputHeight: 38px; + --universalBorderRadius: 10px; --formBackgroundColor: #fff; --formSubBackgroundColor: #f5f5f5; --formTextColor: #000; @@ -9,6 +10,10 @@ form.semanticForms { --placeholderColor: #aaa; --scrollbarColor: #c0c0c0; --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + --border: 1px var(--borderColor) solid; + --clearButtonColor: #000; + --buttonGradientLight: #fff; + --buttonGradientDark: #c0c0c0; } form.semanticForms.dark { --formBackgroundColor: #555; @@ -20,6 +25,10 @@ form.semanticForms.dark { --placeholderColor: #C9C9C9; --scrollbarColor: #373737; --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + --border: none; + --clearButtonColor: #fff; + --buttonGradientLight: #6f6f6f; + --buttonGradientDark: #373737; } form.semanticForms * { box-sizing: border-box; @@ -32,7 +41,9 @@ form.semanticForms { width: 100%; } form.semanticForms fieldset { - border-radius: 10px; + display: flex; + flex-direction: column; + border-radius: var(--universalBorderRadius); padding: 20px 10px; margin-bottom: 15px; background: var(--formSubBackgroundColor); @@ -82,14 +93,19 @@ form.semanticForms .radios ul { form.semanticForms dd { position: relative; } +form.semanticForms label { + user-select: none; + color: var(--placeholderColor); + touch-action: manipulation; +} form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), form.semanticForms select, form.semanticForms textarea { background: var(--formBackgroundColor); - border: 1px var(--borderColor) solid; + border: var(--border); color: var(--formTextColor); width: 100%; - border-radius: 5px; + border-radius: var(--universalBorderRadius); font-size: 16px; touch-action: manipulation; } @@ -122,26 +138,16 @@ form.semanticForms input:not([type='submit']):not([type='reset']):not([type='ima form.semanticForms select { height: var(--inputHeight); } -form.semanticForms label { - color: var(--placeholderColor); - touch-action: manipulation; -} -form.semanticForms textarea { - min-width: 100%; - width: 100%; - min-height: 38px; - height: 100px; -} -@supports (scrollbar-color: auto) { - form.semanticForms textarea { - scrollbar-color: var(--scrollbarColor) var(--formBackgroundColor); - } -} form.semanticForms input[type=color] { padding: 4px !important; padding-right: 30px !important; height: var(--inputHeight); } +form.semanticForms input[type=checkbox], +form.semanticForms input[type=radio] { + width: 1.3em; + height: 1.3em; +} form.semanticForms select { cursor: pointer; background-image: var(--selectIcon); @@ -152,7 +158,18 @@ form.semanticForms select { -moz-appearance: none; appearance: none; } -form.semanticForms .clear { +form.semanticForms textarea { + resize: vertical; + width: 100%; + min-height: 38px; + height: 100px; +} +@supports (scrollbar-color: auto) { + form.semanticForms textarea { + scrollbar-color: var(--scrollbarColor) var(--formBackgroundColor); + } +} +form.semanticForms button.clear { cursor: pointer; appearance: none; -webkit-appearance: none; @@ -164,13 +181,13 @@ form.semanticForms .clear { padding: 5px; background: none; border: none; - color: var(--placeholderColor); + color: var(--clearButtonColor); display: flex; align-items: center; justify-content: center; } -form.semanticForms .clear:hover, -form.semanticForms .clear:focus { +form.semanticForms button.clear:hover, +form.semanticForms button.clear:focus { filter: brightness(0.8); } form.semanticForms textarea + label + .clear { @@ -186,12 +203,35 @@ form.semanticForms input[type='submit'], form.semanticForms input[type='reset'], form.semanticForms input[type='image'], form.semanticForms button:not(.clear) { + max-width: max-content; cursor: pointer; - background: var(--buttonBackgroundColor); + background-image: linear-gradient(to bottom, var(--buttonGradientLight) 0%, var(--buttonGradientDark) 100%); color: var(--formTextColor); - border: 1px var(--borderColor) solid; - border-radius: 5px; - padding: 10px; + border: 2px var(--buttonGradientDark) solid; + border-radius: 20px; + padding: 5px 25px; + margin: 25px 10px; + font-size: 100%; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + transition: filter 0.1s; +} +form.semanticForms input[type='submit']:hover, +form.semanticForms input[type='reset']:hover, +form.semanticForms input[type='image']:hover, +form.semanticForms button:not(.clear):hover { + filter: brightness(1.2); +} +form.semanticForms input[type='submit']:active, +form.semanticForms input[type='reset']:active, +form.semanticForms input[type='image']:active, +form.semanticForms button:not(.clear):active, +form.semanticForms input[type='submit']:focus, +form.semanticForms input[type='reset']:focus, +form.semanticForms input[type='image']:focus, +form.semanticForms button:not(.clear):focus { + background-image: linear-gradient(to bottom, var(--buttonGradientDark) 0%, var(--buttonGradientLight) 100%); } form.semanticForms input::placeholder, form.semanticForms textarea::placeholder { diff --git a/semanticForms.js b/semanticForms.js index 250e0ee..6138a37 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -3,33 +3,30 @@ window.semanticForms = () => { if (typeof document.getElementsByClassName !== 'function' || typeof document.querySelector !== 'function' || !document.body.classList || !window.MutationObserver) return const nodeNameLookup = ['TEXTAREA', 'SELECT'] - const typeLookup = ['checkbox', 'color', 'date', 'datetime-local', 'email', 'file', 'image', 'month', 'number', 'password', 'radio', 'range', 'search', 'tel', 'text', 'time', 'url', 'week'] + const inputTypeLookup = ['checkbox', 'color', 'date', 'datetime-local', 'email', 'file', 'image', 'month', 'number', 'password', 'radio', 'range', 'search', 'tel', 'text', 'time', 'url', 'week'] // progressively enhance form elements that have the semanticForms class const forms = document.querySelectorAll('form.semanticForms:not(.semanticFormsActive)') for (const form of forms) { form.classList.add('semanticFormsActive') - - // collect all form elements - const inputs = Array.from(form.querySelectorAll('input, textarea, select')) - if (form.classList.contains('lowFlow')) continue + // update each input in the semantic form + const inputs = Array.from(form.querySelectorAll('input, textarea, select')) for (const input of inputs) { - // check if input has already been formatted + // ignore input if it has previously been formatted if (input.classList.contains('semanticform') || !input.id) continue const type = input.getAttribute('type') - - if (nodeNameLookup.includes(input.nodeName) || typeLookup.includes(type)) { + if (nodeNameLookup.includes(input.nodeName) || inputTypeLookup.includes(type)) { + // find
    element let dl = input.parentNode while (dl && dl.nodeName !== 'DL') dl = dl.parentNode if (!dl) continue if (!dl.classList.contains('floatLabelForm')) dl.classList.add('floatLabelForm') let label - if (input.parentNode.parentNode.id && (type === 'checkbox' || type === 'radio')) { label = document.querySelector('label[data-for=' + input.parentNode.parentNode.id.replace(/\./g, '\\.') + ']') } else { @@ -38,10 +35,11 @@ window.semanticForms = () => { input.classList.add('semanticform') - // checkboxes and radios + // specific handling of checkboxes and radios if (type === 'checkbox' || type === 'radio') { let dd = input.parentNode while (dd && dd.nodeName !== 'DD') dd = dd.parentNode + if (dd.firstChild.nodeName !== 'LABEL') { const newLabel = document.createElement('label') newLabel.className = 'floatLabelFormAnimatedLabel' @@ -64,6 +62,7 @@ window.semanticForms = () => { if (dd.parentElement.nodeName === 'DIV') { dd.parentElement.remove() } + div.append(label.closest('dt'), dd) dl.append(div) } else { @@ -117,6 +116,7 @@ window.semanticForms = () => { }) } + // todo: is there a way to append the button via DOM manip. to the textarea, removing all code below??? // add listener to shift clear button when scrollbar present for (const textarea of document.querySelectorAll('textarea')) { // shifts the close button to the right if a scrollbar is present diff --git a/semanticForms.less b/semanticForms.less index 1db4351..b1f63a5 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -1,6 +1,7 @@ -// setup global colors +// setup global styles form.semanticForms { --inputHeight: 38px; + --universalBorderRadius: 10px; --formBackgroundColor: #fff; --formSubBackgroundColor: #f5f5f5; --formTextColor: #000; @@ -10,6 +11,10 @@ form.semanticForms { --placeholderColor: #aaa; --scrollbarColor: #c0c0c0; --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + --border: 1px var(--borderColor) solid; + --clearButtonColor: #000; + --buttonGradientLight: #fff; + --buttonGradientDark: #c0c0c0; } form.semanticForms.dark { @@ -22,6 +27,10 @@ form.semanticForms.dark { --placeholderColor: #C9C9C9; --scrollbarColor: #373737; --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + --border: none; + --clearButtonColor: #fff; + --buttonGradientLight: #6f6f6f; + --buttonGradientDark: #373737; } // global override @@ -37,7 +46,9 @@ form.semanticForms { width: 100%; fieldset { - border-radius: 10px; + display: flex; + flex-direction: column; + border-radius: var(--universalBorderRadius); padding: 20px 10px; margin-bottom: 15px; background: var(--formSubBackgroundColor); @@ -97,15 +108,21 @@ form.semanticForms { position: relative; } + label { + user-select: none; + color: var(--placeholderColor); + touch-action: manipulation; + } + // style all input types input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), select, textarea { background: var(--formBackgroundColor); - border: 1px var(--borderColor) solid; + border: var(--border); color: var(--formTextColor); width: 100%; - border-radius: 5px; + border-radius: var(--universalBorderRadius); font-size: 16px; touch-action: manipulation; @@ -134,25 +151,6 @@ form.semanticForms { height: var(--inputHeight); } - label { - color: var(--placeholderColor); - touch-action: manipulation; - } - - textarea { - min-width: 100%; - width: 100%; - min-height: 38px; - height: 100px; - } - - // update for scrollbars - @supports (scrollbar-color: auto) { - textarea { - scrollbar-color: var(--scrollbarColor) var(--formBackgroundColor); - } - } - // specific styling for color input input[type=color] { padding: 4px !important; @@ -160,6 +158,13 @@ form.semanticForms { height: var(--inputHeight); } + input[type=checkbox], + input[type=radio] { + // 30# times larger based on font size + width: 1.3em; + height: 1.3em; + } + // custom dropdown graphic on select element select { cursor: pointer; @@ -172,6 +177,20 @@ form.semanticForms { appearance: none; } + textarea { + resize: vertical; + width: 100%; + min-height: 38px; + height: 100px; + } + + // update for scrollbars + @supports (scrollbar-color: auto) { + textarea { + scrollbar-color: var(--scrollbarColor) var(--formBackgroundColor); + } + } + // "x" button that appears when a value is entered button.clear { cursor: pointer; @@ -185,7 +204,7 @@ form.semanticForms { padding: 5px; background: none; border: none; - color: var(--placeholderColor); + color: var(--clearButtonColor); display: flex; align-items: center; justify-content: center; @@ -214,12 +233,28 @@ form.semanticForms { input[type='reset'], input[type='image'], button:not(.clear) { + max-width: max-content; cursor: pointer; - background: var(--buttonBackgroundColor); + background-image: linear-gradient(to bottom, var(--buttonGradientLight) 0%, var(--buttonGradientDark) 100%); color: var(--formTextColor); - border: 1px var(--borderColor) solid; - border-radius: 5px; - padding: 10px; + border: 2px var(--buttonGradientDark) solid; + border-radius: 20px; + padding: 5px 25px; + margin: 25px 10px; + font-size: 100%; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + transition: filter 0.1s; + + &:hover { + filter: brightness(1.2); + } + + &:active, + &:focus { + background-image: linear-gradient(to bottom, var(--buttonGradientDark) 0%, var(--buttonGradientLight) 100%); + } } // style placeholders From 52e2c74c5435a3af56935c9e63b7e1f153917b86 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Wed, 4 Sep 2024 11:15:40 -0400 Subject: [PATCH 11/60] tweaks --- semanticForms.css | 17 +++++++++-------- semanticForms.less | 17 +++++++++-------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index b61062f..f8cd88b 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -1,6 +1,4 @@ form.semanticForms { - --inputHeight: 38px; - --universalBorderRadius: 10px; --formBackgroundColor: #fff; --formSubBackgroundColor: #f5f5f5; --formTextColor: #000; @@ -9,11 +7,13 @@ form.semanticForms { --subBorderColor: #c0c0c0; --placeholderColor: #aaa; --scrollbarColor: #c0c0c0; - --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - --border: 1px var(--borderColor) solid; --clearButtonColor: #000; --buttonGradientLight: #fff; --buttonGradientDark: #c0c0c0; + --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + --inputHeight: 38px; + --borderRadius: 10px; + --border: 1px var(--borderColor) solid; } form.semanticForms.dark { --formBackgroundColor: #555; @@ -24,11 +24,11 @@ form.semanticForms.dark { --subBorderColor: #3f3f3f; --placeholderColor: #C9C9C9; --scrollbarColor: #373737; - --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - --border: none; --clearButtonColor: #fff; --buttonGradientLight: #6f6f6f; --buttonGradientDark: #373737; + --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + --border: none; } form.semanticForms * { box-sizing: border-box; @@ -43,7 +43,8 @@ form.semanticForms { form.semanticForms fieldset { display: flex; flex-direction: column; - border-radius: var(--universalBorderRadius); + gap: 10px; + border-radius: var(--borderRadius); padding: 20px 10px; margin-bottom: 15px; background: var(--formSubBackgroundColor); @@ -105,7 +106,7 @@ form.semanticForms textarea { border: var(--border); color: var(--formTextColor); width: 100%; - border-radius: var(--universalBorderRadius); + border-radius: var(--borderRadius); font-size: 16px; touch-action: manipulation; } diff --git a/semanticForms.less b/semanticForms.less index b1f63a5..ffc30c3 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -1,7 +1,5 @@ // setup global styles form.semanticForms { - --inputHeight: 38px; - --universalBorderRadius: 10px; --formBackgroundColor: #fff; --formSubBackgroundColor: #f5f5f5; --formTextColor: #000; @@ -10,11 +8,13 @@ form.semanticForms { --subBorderColor: #c0c0c0; --placeholderColor: #aaa; --scrollbarColor: #c0c0c0; - --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - --border: 1px var(--borderColor) solid; --clearButtonColor: #000; --buttonGradientLight: #fff; --buttonGradientDark: #c0c0c0; + --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + --inputHeight: 38px; + --borderRadius: 10px; + --border: 1px var(--borderColor) solid; } form.semanticForms.dark { @@ -26,11 +26,11 @@ form.semanticForms.dark { --subBorderColor: #3f3f3f; --placeholderColor: #C9C9C9; --scrollbarColor: #373737; - --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - --border: none; --clearButtonColor: #fff; --buttonGradientLight: #6f6f6f; --buttonGradientDark: #373737; + --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); + --border: none; } // global override @@ -48,7 +48,8 @@ form.semanticForms { fieldset { display: flex; flex-direction: column; - border-radius: var(--universalBorderRadius); + gap: 10px; + border-radius: var(--borderRadius); padding: 20px 10px; margin-bottom: 15px; background: var(--formSubBackgroundColor); @@ -122,7 +123,7 @@ form.semanticForms { border: var(--border); color: var(--formTextColor); width: 100%; - border-radius: var(--universalBorderRadius); + border-radius: var(--borderRadius); font-size: 16px; touch-action: manipulation; From b8f56d1cb7b1d329921ab9c8d6a7e84b9a319ed4 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Wed, 4 Sep 2024 11:21:54 -0400 Subject: [PATCH 12/60] remove ref files --- semanticForms copy.css | 279 ------------------ semanticForms copy.less | 638 ---------------------------------------- 2 files changed, 917 deletions(-) delete mode 100644 semanticForms copy.css delete mode 100644 semanticForms copy.less diff --git a/semanticForms copy.css b/semanticForms copy.css deleted file mode 100644 index 37dc732..0000000 --- a/semanticForms copy.css +++ /dev/null @@ -1,279 +0,0 @@ -form.semanticForms input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), -form.semanticForms textarea { - background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23000' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); - background-size: 12px; - background-repeat: no-repeat; -} -form.semanticForms input:not([type=checkbox]):not([type=radio]) { - background-position: right -12px center; -} -form.semanticForms textarea { - background-position: right -12px top 10px; - height: 100px; -} -form.semanticForms select { - background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - background-size: 14px; - background-position: calc(99%) 16px; - background-repeat: no-repeat; - width: 292px; - height: 37px; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; -} -form.semanticForms input::placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms textarea::placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms input:focus::placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms input:focus::-moz-placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms input:focus::-webkit-input-placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms input:focus:-ms-input-placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms textarea:focus::placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms textarea:focus::-moz-placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms textarea:focus::-webkit-input-placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms textarea:focus:-ms-input-placeholder { - color: #aaa; - opacity: 1; -} -form.semanticForms label.floatLabelFormAnimatedLabel, -form.semanticForms input:not([type=checkbox]):not([type=radio]), -form.semanticForms select, -form.semanticForms textarea, -form.semanticForms section { - transition: color 0.2s, text-indent 0.2s, transform 0.2s, background-position 0.2s; - touch-action: manipulation; -} -form.semanticForms .floatLabelForm { - margin: 0 auto; -} -form.semanticForms .floatLabelForm input[disabled] { - opacity: 0.5; -} -form.semanticForms .floatLabelForm input:not([type=date])::-webkit-clear-button { - -webkit-appearance: none; - margin: 0; -} -form.semanticForms .floatLabelForm dd { - float: left; - margin: 0 10px 0 10px; -} -form.semanticForms .floatLabelForm dt:not(.checkboxes):not(.radios) { - font-size: 1px; - text-indent: 100%; - white-space: nowrap; - overflow: hidden; - position: absolute; - right: 9999px; -} -form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios) { - display: flex; - flex-flow: column-reverse; -} -form.semanticForms .floatLabelForm .checkboxes ul, -form.semanticForms .floatLabelForm .radios ul { - margin: 3px 20px 0 0; - width: 262px; - padding-left: 10px; -} -form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios).singleCheckbox { - width: 292px; - display: flex; - flex-direction: row-reverse; - align-items: flex-start; - justify-content: left; -} -form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios).singleCheckbox label { - margin-top: 10px; -} -form.semanticForms .floatLabelForm dd:not(.checkboxes):not(.radios).singleCheckbox input { - margin: 10px 10px 0 0; -} -form.semanticForms .floatLabelForm input.x { - background-position: right 6px center; -} -form.semanticForms .floatLabelForm textarea.x { - background-position: right 6px top 10px; -} -form.semanticForms .floatLabelForm .onX { - cursor: pointer; -} -form.semanticForms .floatLabelForm input:-webkit-autofill, -form.semanticForms .floatLabelForm input:-webkit-autofill:hover, -form.semanticForms .floatLabelForm input:-webkit-autofill:focus, -form.semanticForms .floatLabelForm input:-webkit-autofill:active, -form.semanticForms .floatLabelForm textarea:-webkit-autofill, -form.semanticForms .floatLabelForm textarea:-webkit-autofill:hover, -form.semanticForms .floatLabelForm textarea:-webkit-autofill:focus, -form.semanticForms .floatLabelForm textarea:-webkit-autofill:active, -form.semanticForms .floatLabelForm select:-webkit-autofill, -form.semanticForms .floatLabelForm select:-webkit-autofill:hover, -form.semanticForms .floatLabelForm select:-webkit-autofill:focus, -form.semanticForms .floatLabelForm select:-webkit-autofill:active { - -webkit-box-shadow: 0 0 0 1000px #fff inset; - transition: background-color 5000s ease-in-out 0s, color 5000s ease-in-out 0s; - transition-delay: 5000s; - transition-property: background-color, color; -} -form.semanticForms .floatLabelForm::after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -@media (min-width: 700px) { - form.semanticForms .floatLabelForm { - margin: 0 -10px; - width: auto; - text-align: left; - } - form.semanticForms fieldset { - text-align: left; - } - form.semanticForms fieldset input[type='submit'], - form.semanticForms fieldset input[type='reset'], - form.semanticForms fieldset input[type='image'], - form.semanticForms fieldset button { - float: left; - clear: none; - } - form.semanticForms fieldset :last-child { - margin-right: 0; - } - form.semanticForms .x2 input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), - form.semanticForms .x2 select, - form.semanticForms .x2 textarea { - width: 562px; - } - form.semanticForms .x2 input[type=color] { - width: 604px; - } - form.semanticForms .x2 input[type=range] { - width: 560px !important; - } - form.semanticForms .x2 select { - width: 604px; - } - form.semanticForms .x2.checkboxes ul, - form.semanticForms .x2.radios ul { - width: 574px; - } - form.semanticForms .x2 label.floatLabelFormAnimatedLabel { - width: 375px; - } -} -form.semanticForms.lowFlow dl { - margin: 10px 0 0 0; -} -form.semanticForms.lowFlow dd { - margin: 0 0 25px 0; -} -form.semanticForms.lowFlow dd:last-child { - margin: 0; -} -form.semanticForms.dark input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), -form.semanticForms.dark textarea { - background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' stroke='%23fff' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23fff' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); -} -form.semanticForms.dark select { - background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - color: #fff; -} -form.semanticForms.dark input::placeholder { - color: #aaa; -} -form.semanticForms.dark textarea::placeholder { - color: #aaa; -} -form.semanticForms.dark input:focus::placeholder { - color: #aaa; -} -form.semanticForms.dark input:focus::-moz-placeholder { - color: #aaa; -} -form.semanticForms.dark input:focus::-webkit-input-placeholder { - color: #aaa; -} -form.semanticForms.dark input:focus:-ms-input-placeholder { - color: #aaa; -} -form.semanticForms.dark textarea:focus::placeholder { - color: #aaa; -} -form.semanticForms.dark textarea:focus::-moz-placeholder { - color: #aaa; -} -form.semanticForms.dark textarea:focus::-webkit-input-placeholder { - color: #aaa; -} -form.semanticForms.dark textarea:focus:-ms-input-placeholder { - color: #aaa; -} -form.semanticForms.dark input[type='submit'], -form.semanticForms.dark input[type='reset'], -form.semanticForms.dark input[type='image'], -form.semanticForms.dark button { - border: 2px #373737 solid; - background-image: linear-gradient(to bottom, #6f6f6f 0%, #373737 100%); - color: #fff; -} -form.semanticForms.dark input[type='submit']:active, -form.semanticForms.dark input[type='reset']:active, -form.semanticForms.dark input[type='image']:active, -form.semanticForms.dark button:active { - background-image: linear-gradient(to bottom, #373737 0%, #6f6f6f 100%); - color: #fff; -} -form.semanticForms.dark .floatLabelForm label.floatLabelFormAnimatedLabel { - color: #aaa; -} -form.semanticForms.dark .floatLabelForm input:not(:placeholder-shown) + label, -form.semanticForms.dark .floatLabelForm input:focus + label, -form.semanticForms.dark .floatLabelForm textarea:not(:placeholder-shown) + label, -form.semanticForms.dark .floatLabelForm textarea:focus + label, -form.semanticForms.dark .floatLabelForm select + label.floatLabelFormAnimatedLabel, -form.semanticForms.dark .floatLabelForm .checkboxes label.floatLabelFormAnimatedLabel, -form.semanticForms.dark .floatLabelForm .radios label.floatLabelFormAnimatedLabel { - color: #fff; -} -form.semanticForms.dark .floatLabelForm input:-webkit-autofill, -form.semanticForms.dark .floatLabelForm input:-webkit-autofill:hover, -form.semanticForms.dark .floatLabelForm input:-webkit-autofill:focus, -form.semanticForms.dark .floatLabelForm input:-webkit-autofill:active, -form.semanticForms.dark .floatLabelForm textarea:-webkit-autofill, -form.semanticForms.dark .floatLabelForm textarea:-webkit-autofill:hover, -form.semanticForms.dark .floatLabelForm textarea:-webkit-autofill:focus, -form.semanticForms.dark .floatLabelForm textarea:-webkit-autofill:active, -form.semanticForms.dark .floatLabelForm select:-webkit-autofill, -form.semanticForms.dark .floatLabelForm select:-webkit-autofill:hover, -form.semanticForms.dark .floatLabelForm select:-webkit-autofill:focus, -form.semanticForms.dark .floatLabelForm select:-webkit-autofill:active { - -webkit-box-shadow: 0 0 0 1000px #555 inset; -} diff --git a/semanticForms copy.less b/semanticForms copy.less deleted file mode 100644 index d2b49fd..0000000 --- a/semanticForms copy.less +++ /dev/null @@ -1,638 +0,0 @@ -// #region variables - -@lightFormBackgroundColor: #fff; -@lightFormSubBackgroundColor: #f5f5f5; -@lightFormTextColor: #000; -@lightBorderColor: #c0c0c0; -@lightPlaceholderColor: #aaa; -@darkFormBackgroundColor: #555; -@darkFormSubBackgroundColor: #2f2f2f; -@darkFormSubBorderColor: #3f3f3f; -@darkFormTextColor: #fff; -@darkBorderColor: #555; -@darkPlaceholderColor: #aaa; -@darkButtonGradientLight: #6f6f6f; -@darkButtonGradientDark: #373737; - -// #endregion - -// #region default (light mode) styles - -form.semanticForms { - - // #region globals - - // font-family: sans-serif; - - // input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), - // select, - // textarea { - // box-sizing: content-box; - // background-color: @lightFormBackgroundColor; - // outline: 0; - // border: 1px @lightBorderColor solid; - // border-radius: 10px; - // width: 250px; - // height: 25px; - // font-size: 100%; - // font-family: sans-serif; - // padding: 5px 20px; - // } - - // input[type=color] { - // background-color: @lightFormBackgroundColor; - // border: 1px @lightBorderColor solid; - // border-radius: 10px; - // width: 292px; - // height: 37px; - // padding: 5px 20px; - // } - - // select { - // box-sizing: border-box; - // } - - // input[type=range] { - // border: 0 !important; - // width: 248px !important; - // } - - // fieldset { - // background-color: @lightFormSubBackgroundColor; - // border: 1px @lightBorderColor solid; - // border-radius: 10px; - // text-align: center; - // margin-bottom: 25px; - - // p { - // text-align: left; - // width: 100%; - // clear: both; - // } - // } - - // legend { - // text-align: left; - // } - - // dl { - // text-align: left; - // } - - // .checkboxes ul, - // .radios ul { - // list-style: none; - // padding: 0; - // } - - // dd.checkboxes, - // dd.radios { - // margin: 0; - // } - - // menu { - // width: 100%; - // clear: both; - // display: flex; - // justify-content: space-between; - // padding: 0; - - // li { - // list-style-type: none; - // } - - // input[type='submit'], - // input[type='reset'], - // input[type='image'], - // button { - // float: none; - // clear: none; - // margin: 0; - // } - // } - - // #endregion - - // #region clear fields and custom select box design - - // input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), - // textarea { - // background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23000' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); - // background-size: 12px; - // background-repeat: no-repeat; - // } - - // input:not([type=checkbox]):not([type=radio]) { - // background-position: right -12px center; - // } - - // textarea { - // background-position: right -12px top 10px; - // height: 100px; - // } - - // select { - // background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - // background-size: 14px; - // background-position: calc(99%) 16px; - // background-repeat: no-repeat; - // width: 292px; - // height: 37px; - // -webkit-appearance: none; - // -moz-appearance: none; - // appearance: none; - // } - - // #endregion - - // #region style placeholders - - // input::placeholder { - // color: @lightPlaceholderColor; - // opacity: 1; - // } - - // textarea::placeholder { - // color: @lightPlaceholderColor; - // opacity: 1; - // } - - // input:focus::placeholder { - // color: @lightPlaceholderColor; - // opacity: 1; - // } - - // input:focus::-moz-placeholder { - // color: @lightPlaceholderColor; - // opacity: 1; - // } - - // input:focus::-webkit-input-placeholder { - // color: @lightPlaceholderColor; - // opacity: 1; - // } - - // input:focus:-ms-input-placeholder { - // color: @lightPlaceholderColor; - // opacity: 1; - // } - - // textarea:focus::placeholder { - // color: @lightPlaceholderColor; - // opacity: 1; - // } - - // textarea:focus::-moz-placeholder { - // color: @lightPlaceholderColor; - // opacity: 1; - // } - - // textarea:focus::-webkit-input-placeholder { - // color: @lightPlaceholderColor; - // opacity: 1; - // } - - // textarea:focus:-ms-input-placeholder { - // color: @lightPlaceholderColor; - // opacity: 1; - // } - - // #endregion - - // #region buttons - - // input[type='submit'], - // input[type='reset'], - // input[type='image'], - // button { - // width: auto; - // box-sizing: content-box; - // float: none; - // clear: both; - // outline: 0; - // -webkit-appearance: none; - // -moz-appearance: none; - // appearance: none; - // border-radius: 20px; - // font-size: 100%; - // margin: 25px 10px; - // padding: 5px 25px; - // border: 2px @lightBorderColor solid; - // background-image: linear-gradient(to bottom, @lightFormBackgroundColor 0%, @lightBorderColor 100%); - // } - - // input[type='submit']:first-of-type, - // input[type='reset']:first-of-type, - // input[type='image']:first-of-type, - // button:first-of-type { - // margin-left: 0; - // } - - // input[type='submit']:active, - // input[type='reset']:active, - // input[type='image']:active, - // button:active { - // background-image: linear-gradient(to bottom, @lightBorderColor 0%, @lightFormBackgroundColor 100%); - // } - - // #endregion - - // #region float label forms - - // label.floatLabelFormAnimatedLabel, input:not([type=checkbox]):not([type=radio]), select, textarea, section { - // transition: color 0.2s, text-indent 0.2s, transform 0.2s, background-position 0.2s; - // touch-action: manipulation; - // } - - .floatLabelForm { - margin: 0 auto; - - input[disabled] { - opacity: 0.5; - } - - // remove native clear button, we made a custom one - input:not([type=date])::-webkit-clear-button { - -webkit-appearance: none; - margin: 0; - } - - dd { - float: left; - margin: 0 10px 0 10px; - } - - // dt:not(.checkboxes):not(.radios) { - // font-size: 1px; - // text-indent: 100%; - // white-space: nowrap; - // overflow: hidden; - // position: absolute; - // right: 9999px; - // } - - // dd:not(.checkboxes):not(.radios) { - // display: flex; - // flex-flow: column-reverse; - // } - - // .checkboxes ul, - // .radios ul { - // margin: 3px 20px 0 0; - // width: 262px; - // padding-left: 10px; - // } - - // label.floatLabelFormAnimatedLabel { - // width: 170px; - // padding: 6px 15px; - // font-size: 75%; - // color: @lightPlaceholderColor; - // cursor: text; - // white-space: nowrap; - // overflow: hidden; - // text-overflow: ellipsis; - // transform-origin: left bottom; - // transform: translate(0, 38px) scale(1.5); - // } - - // dd:not(.checkboxes):not(.radios).singleCheckbox { - // width: 292px; - // display: flex; - // flex-direction: row-reverse; - // align-items: flex-start; - // justify-content: left; - - // label { - // margin-top: 10px; - // } - - // input { - // margin: 10px 10px 0 0; - // } - // } - - // hide placeholder content until the input is focused - // ::placeholder { - // opacity: 0; - // transition: inherit; - // } - - // ::-moz-placeholder { - // opacity: 0; - // transition: inherit; - // } - - // ::-webkit-input-placeholder { - // opacity: 0; - // transition: inherit; - // } - - // :-ms-input-placeholder { - // opacity: 0; - // transition: inherit; - // } - - // show the placeholder when the input is focused - // input:focus::placeholder { - // opacity: 1; - // } - - // input:focus::-moz-placeholder { - // opacity: 1; - // } - - // input:focus::-webkit-input-placeholder { - // opacity: 1; - // } - - // input:focus:-ms-input-placeholder { - // opacity: 1; - // } - - // textarea:focus::placeholder { - // opacity: 1; - // } - - // textarea:focus::-moz-placeholder { - // opacity: 1; - // } - - // textarea:focus::-webkit-input-placeholder { - // opacity: 1; - // } - - // textarea:focus:-ms-input-placeholder { - // opacity: 1; - // } - - // // move the label off of input to make room for input content - // input:not(:placeholder-shown) + label, - // input:focus + label, - // textarea:not(:placeholder-shown) + label, - // textarea:focus + label, - // select + label.floatLabelFormAnimatedLabel, - // .checkboxes label.floatLabelFormAnimatedLabel, - // .radios label.floatLabelFormAnimatedLabel { - // transform: translate(0, 0) scale(1); - // text-indent: 6px; - // cursor: default; - // color: @lightFormTextColor; - // } - - input.x { - background-position: right 6px center; - } - - textarea.x { - background-position: right 6px top 10px; - } - - .onX { - cursor: pointer; - } - - // disable autofill yellow - input:-webkit-autofill, - input:-webkit-autofill:hover, - input:-webkit-autofill:focus, - input:-webkit-autofill:active, - textarea:-webkit-autofill, - textarea:-webkit-autofill:hover, - textarea:-webkit-autofill:focus, - textarea:-webkit-autofill:active, - select:-webkit-autofill, - select:-webkit-autofill:hover, - select:-webkit-autofill:focus, - select:-webkit-autofill:active { - -webkit-box-shadow: 0 0 0 1000px @lightFormBackgroundColor inset; - transition: background-color 5000s ease-in-out 0s, color 5000s ease-in-out 0s; - transition-delay: 5000s; - transition-property: background-color, color; - } - } - - .floatLabelForm::after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; - } - - // #endregion - - // #region side-by-side pattern on large screens - - @media (min-width: 700px) { - .floatLabelForm { - margin: 0 -10px; - width: auto; - text-align: left; - } - - fieldset { - text-align: left; - - input[type='submit'], - input[type='reset'], - input[type='image'], - button { - float: left; - clear: none; - } - - :last-child { - margin-right: 0; - } - } - - .x2 { - input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), - select, - textarea { - width: 562px; - } - } - - .x2 { - input[type=color] { - width: 604px; - } - } - - .x2 { - input[type=range] { - width: 560px !important; - } - } - - .x2 { - select { - width: 604px; - } - } - - .x2.checkboxes ul, - .x2.radios ul { - width: 574px; - } - - .x2 { - label.floatLabelFormAnimatedLabel { - width: 375px; - } - } - } - - // #endregion -} - -// #endregion - -// #region non-js exclusive styles - -form.semanticForms.lowFlow { - dl { - margin: 10px 0 0 0; - } - - dd { - margin: 0 0 25px 0; - } - - dd:last-child { - margin: 0; - } -} - -// #endregion - -// #region dark mode styles - -form.semanticForms.dark { - // input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type=color]), - // select, - // textarea { - // background-color: @darkFormBackgroundColor; - // border: 1px @darkBorderColor solid; - // color: @darkFormTextColor; - // } - - // input[type=color] { - // background-color: @darkFormBackgroundColor; - // border: 1px @darkBorderColor solid; - // color: @darkFormTextColor; - // } - - // fieldset { - // background-color: @darkFormSubBackgroundColor; - // border: 1px @darkFormSubBorderColor solid; - // } - - // clear fields - input:not([type='submit']):not([type='reset']):not([type=checkbox]):not([type=radio]), - textarea { - background-image: url("data:image/svg+xml;utf8,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' stroke='%23fff' viewBox='0 0 1000 1000' enable-background='new 0 0 1000 1000' xml:space='preserve'%3E%3Cg%3E%3Cpath fill='%23fff' d='M964.7,157.6L622.3,500l342.4,342.4l0,0c15.7,15.7,25.3,37.3,25.3,61.1c0,47.7-38.7,86.5-86.5,86.5c-23.9,0-45.5-9.7-61.1-25.3l0,0L500,622.3L157.6,964.7l0,0C142,980.3,120.3,990,96.5,990C48.7,990,10,951.3,10,903.5c0-23.9,9.7-45.5,25.3-61.1l0,0L377.7,500L35.3,157.6l0,0C19.7,142,10,120.3,10,96.5C10,48.7,48.7,10,96.5,10c23.9,0,45.5,9.7,61.1,25.3l0,0L500,377.7L842.4,35.3l0,0C858,19.7,879.7,10,903.5,10c47.8,0,86.5,38.7,86.5,86.5C990,120.3,980.3,142,964.7,157.6L964.7,157.6z'/%3E%3C/g%3E%3C/svg%3E"); - } - - // custom select box design - select { - background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); - color: @darkFormTextColor; - } - - // style placeholders - input::placeholder { - color: @darkPlaceholderColor; - } - - textarea::placeholder { - color: @darkPlaceholderColor; - } - - input:focus::placeholder { - color: @darkPlaceholderColor; - } - - input:focus::-moz-placeholder { - color: @darkPlaceholderColor; - } - - input:focus::-webkit-input-placeholder { - color: @darkPlaceholderColor; - } - - input:focus:-ms-input-placeholder { - color: @darkPlaceholderColor; - } - - textarea:focus::placeholder { - color: @darkPlaceholderColor; - } - - textarea:focus::-moz-placeholder { - color: @darkPlaceholderColor; - } - - textarea:focus::-webkit-input-placeholder { - color: @darkPlaceholderColor; - } - - textarea:focus:-ms-input-placeholder { - color: @darkPlaceholderColor; - } - - // buttons - input[type='submit'], - input[type='reset'], - input[type='image'], - button { - border: 2px @darkButtonGradientDark solid; - background-image: linear-gradient(to bottom, @darkButtonGradientLight 0%, @darkButtonGradientDark 100%); - color: @darkFormTextColor; - } - - input[type='submit']:active, - input[type='reset']:active, - input[type='image']:active, - button:active { - background-image: linear-gradient(to bottom, @darkButtonGradientDark 0%, @darkButtonGradientLight 100%); - color: @darkFormTextColor; - } - - .floatLabelForm { - label.floatLabelFormAnimatedLabel { - color: @darkPlaceholderColor; - } - - // move the label off of input to make room for input content - input:not(:placeholder-shown) + label, - input:focus + label, - textarea:not(:placeholder-shown) + label, - textarea:focus + label, - select + label.floatLabelFormAnimatedLabel, - .checkboxes label.floatLabelFormAnimatedLabel, - .radios label.floatLabelFormAnimatedLabel { - color: @darkFormTextColor; - } - - // disable autofill yellow - input:-webkit-autofill, - input:-webkit-autofill:hover, - input:-webkit-autofill:focus, - input:-webkit-autofill:active, - textarea:-webkit-autofill, - textarea:-webkit-autofill:hover, - textarea:-webkit-autofill:focus, - textarea:-webkit-autofill:active, - select:-webkit-autofill, - select:-webkit-autofill:hover, - select:-webkit-autofill:focus, - select:-webkit-autofill:active { - -webkit-box-shadow: 0 0 0 1000px @darkFormBackgroundColor inset; - } - } -} - -// #endregion From 9e0b067a2858eecc77f47befe0290b56f5be3048 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Thu, 5 Sep 2024 12:28:20 -0400 Subject: [PATCH 13/60] add utility classes --- CHANGELOG.md | 1 + semanticForms.css | 176 ++++++++++++++++++++----------------- semanticForms.html | 4 +- semanticForms.js | 9 +- semanticForms.less | 211 +++++++++++++++++++++++++++------------------ 5 files changed, 237 insertions(+), 164 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57d33d8..797e474 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Fieldset elements now utilize CSS grid to dynamically fill available space before wrapping to the next row. - Input clear button is now a button element, allowing interaction via tab. - Input clear button avoids overlap with scrollbars on textarea elements. + - Added multiple utility classes that define how wide inputs will span. ## 3.2.1 diff --git a/semanticForms.css b/semanticForms.css index f8cd88b..81b4c79 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -14,6 +14,8 @@ form.semanticForms { --inputHeight: 38px; --borderRadius: 10px; --border: 1px var(--borderColor) solid; + --inputTopMargin: 15px; + --inputMinWidth: 250px; } form.semanticForms.dark { --formBackgroundColor: #555; @@ -30,81 +32,68 @@ form.semanticForms.dark { --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); --border: none; } +form.semanticForms { + width: 100%; +} form.semanticForms * { + color: var(--formTextColor); box-sizing: border-box; + font-family: sans-serif; margin: 0; padding: 0; - font-family: sans-serif; -} -form.semanticForms { - color: var(--formTextColor); - width: 100%; } form.semanticForms fieldset { display: flex; flex-direction: column; - gap: 10px; - border-radius: var(--borderRadius); + gap: 5px; padding: 20px 10px; margin-bottom: 15px; + border-radius: var(--borderRadius); background: var(--formSubBackgroundColor); border: 1px var(--subBorderColor) solid; } form.semanticForms fieldset dl { display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(var(--inputMinWidth), 1fr)); gap: 10px; margin-bottom: 10px; } -form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios) { +form.semanticForms fieldset dl dd { + position: relative; +} +form.semanticForms fieldset dl dd:not(.checkboxes, .radios) { display: flex; gap: 10px; max-width: 500px; } -form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios):not(.singleCheckbox) { +form.semanticForms fieldset dl dd:not(.checkboxes, .radios):not(.singleCheckbox) { flex-direction: column; } -form.semanticForms fieldset dl dd:not(.checkboxes):not(.radios) label { - cursor: pointer; +form.semanticForms fieldset dl dd.checkboxes ul, +form.semanticForms fieldset dl dd.radios ul { + display: flex; + flex-direction: column; + margin-top: var(--inputTopMargin); + padding-left: 10px; + gap: 5px; } form.semanticForms menu, form.semanticForms ul { display: flex; justify-content: space-between; - padding: 5px; + flex-wrap: wrap; + gap: 10px; list-style-type: none; } -form.semanticForms dt { - position: relative; -} -form.semanticForms dt label[data-for="checkboxes"], -form.semanticForms dt label[data-for="radios"] { - position: absolute; - transform: translateY(-100%) scale(0.8); - top: 10px; -} -form.semanticForms .checkboxes ul, -form.semanticForms .radios ul { - padding-left: 10px; - margin-top: 5px; - display: flex; - flex-direction: column; - gap: 4px; -} -form.semanticForms dd { - position: relative; -} -form.semanticForms label { - user-select: none; - color: var(--placeholderColor); - touch-action: manipulation; +form.semanticForms details[open], +form.semanticForms summary { + margin-bottom: 10px; } form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), form.semanticForms select, form.semanticForms textarea { background: var(--formBackgroundColor); border: var(--border); - color: var(--formTextColor); width: 100%; border-radius: var(--borderRadius); font-size: 16px; @@ -148,6 +137,7 @@ form.semanticForms input[type=checkbox], form.semanticForms input[type=radio] { width: 1.3em; height: 1.3em; + cursor: pointer; } form.semanticForms select { cursor: pointer; @@ -165,17 +155,13 @@ form.semanticForms textarea { min-height: 38px; height: 100px; } -@supports (scrollbar-color: auto) { - form.semanticForms textarea { - scrollbar-color: var(--scrollbarColor) var(--formBackgroundColor); - } -} form.semanticForms button.clear { cursor: pointer; appearance: none; -webkit-appearance: none; position: absolute; - top: 10px; + height: min-content; + top: var(--inputTopMargin); bottom: 0; right: 0; margin: auto 6px; @@ -207,11 +193,9 @@ form.semanticForms button:not(.clear) { max-width: max-content; cursor: pointer; background-image: linear-gradient(to bottom, var(--buttonGradientLight) 0%, var(--buttonGradientDark) 100%); - color: var(--formTextColor); border: 2px var(--buttonGradientDark) solid; border-radius: 20px; padding: 5px 25px; - margin: 25px 10px; font-size: 100%; -webkit-appearance: none; -moz-appearance: none; @@ -239,24 +223,40 @@ form.semanticForms textarea::placeholder { color: var(--placeholderColor); opacity: 1; } -form.semanticForms input:not(:placeholder-shown) + label, -form.semanticForms input:focus + label, -form.semanticForms textarea:not(:placeholder-shown) + label, -form.semanticForms textarea:focus + label, -form.semanticForms select + label.floatLabelFormAnimatedLabel, -form.semanticForms .checkboxes label.floatLabelFormAnimatedLabel, -form.semanticForms .radios label.floatLabelFormAnimatedLabel, -form.semanticForms dt > label { - color: var(--formTextColor); +form.semanticForms .floatLabelForm { + container-type: inline-size; } form.semanticForms .floatLabelForm div { position: relative; + width: 100%; +} +form.semanticForms .floatLabelForm div.span-1 dd, +form.semanticForms .floatLabelForm div.span-2 dd, +form.semanticForms .floatLabelForm div.span-3 dd, +form.semanticForms .floatLabelForm div.span-4 dd, +form.semanticForms .floatLabelForm div.span-5 dd { + max-width: 100% !important; +} +form.semanticForms .floatLabelForm div.span-1 { + grid-column: span 1; +} +form.semanticForms .floatLabelForm div.span-2 { + grid-column: span 2; +} +form.semanticForms .floatLabelForm div.span-3 { + grid-column: span 3; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) label { +form.semanticForms .floatLabelForm div.span-4 { + grid-column: span 4; +} +form.semanticForms .floatLabelForm div.span-5 { + grid-column: span 5; +} +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) label { position: absolute; transform-origin: left center; pointer-events: none; - top: 20px; + top: calc(var(--inputTopMargin) + 10px); left: 8px; transition: transform 250ms; cursor: text; @@ -264,47 +264,60 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes): overflow: hidden; text-overflow: ellipsis; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) select { - margin-top: 10px; +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) select { + margin-top: var(--inputTopMargin); } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input::placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea::placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input::placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea::placeholder { opacity: 0; transition: inherit; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input::-moz-placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea::-moz-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input::-moz-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea::-moz-placeholder { opacity: 0; transition: inherit; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input::-webkit-input-placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea::-webkit-input-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input::-webkit-input-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea::-webkit-input-placeholder { opacity: 0; transition: inherit; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input:-ms-input-placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea:-ms-input-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input:-ms-input-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea:-ms-input-placeholder { opacity: 0; transition: inherit; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input:focus::placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea:focus::placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input:focus::placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea:focus::placeholder { opacity: 1; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input:focus::-moz-placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea:focus::-moz-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input:focus::-moz-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea:focus::-moz-placeholder { opacity: 1; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input:focus::-webkit-input-placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea:focus::-webkit-input-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input:focus::-webkit-input-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea:focus::-webkit-input-placeholder { opacity: 1; } -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) input:focus:-ms-input-placeholder, -form.semanticForms .floatLabelForm div dd:not(.singleCheckbox):not(.checkboxes):not(.radios) textarea:focus:-ms-input-placeholder { +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input:focus:-ms-input-placeholder, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea:focus:-ms-input-placeholder { opacity: 1; } +form.semanticForms .floatLabelForm div dt { + position: relative; +} +form.semanticForms .floatLabelForm div dt label:is([data-for="checkboxes"], [data-for="radios"]) { + position: absolute; + transform: translateY(-100%) scale(0.8); + top: var(--inputTopMargin); +} +form.semanticForms .floatLabelForm div label { + user-select: none; + color: var(--placeholderColor); + touch-action: manipulation; +} form.semanticForms .floatLabelForm input:-webkit-autofill, form.semanticForms .floatLabelForm input:-webkit-autofill:hover, form.semanticForms .floatLabelForm input:-webkit-autofill:focus, @@ -322,6 +335,11 @@ form.semanticForms .floatLabelForm select:-webkit-autofill:active { transition-delay: 5000s; transition-property: background-color, color; } +@supports (scrollbar-color: auto) { + form.semanticForms textarea { + scrollbar-color: var(--scrollbarColor) var(--formBackgroundColor); + } +} form.semanticForms.lowFlow fieldset dl { display: flex; flex-direction: column; @@ -331,3 +349,7 @@ form.semanticForms.lowFlow fieldset dd { flex-direction: row !important; margin-bottom: 10px; } +form.semanticForms.lowFlow .checkboxes ul, +form.semanticForms.lowFlow .radios ul { + margin-top: calc(var(--inputTopMargin) / 2); +} diff --git a/semanticForms.html b/semanticForms.html index 2cccbac..8ea13d3 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -104,7 +104,7 @@

    Semantic Forms

    -
    +
    @@ -122,7 +122,7 @@

    Semantic Forms

    -
    +
    diff --git a/semanticForms.js b/semanticForms.js index 6138a37..c84bee0 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -94,10 +94,15 @@ window.semanticForms = () => { input.value = '' input.focus() }) - insertAfter(clearBtn, dd.querySelector('label')) } + if (/span-/.test(dd.className)) { + const match = dd.className.match(/span-[0-9]/)[0] + dd.classList.remove(match) + div.classList.add(match) + } + div.append(dt, dd) dl.append(div) if (dt.style.display === 'none' && dd.style.display === 'none') { @@ -116,7 +121,7 @@ window.semanticForms = () => { }) } - // todo: is there a way to append the button via DOM manip. to the textarea, removing all code below??? + // TODO investigate appending the button via DOM manipulation // add listener to shift clear button when scrollbar present for (const textarea of document.querySelectorAll('textarea')) { // shifts the close button to the right if a scrollbar is present diff --git a/semanticForms.less b/semanticForms.less index ffc30c3..4f0f6e9 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -1,4 +1,4 @@ -// setup global styles +// #region global styles form.semanticForms { --formBackgroundColor: #fff; --formSubBackgroundColor: #f5f5f5; @@ -15,6 +15,8 @@ form.semanticForms { --inputHeight: 38px; --borderRadius: 10px; --border: 1px var(--borderColor) solid; + --inputTopMargin: 15px; + --inputMinWidth: 250px; } form.semanticForms.dark { @@ -32,46 +34,59 @@ form.semanticForms.dark { --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); --border: none; } - -// global override -form.semanticForms * { - box-sizing: border-box; - margin: 0; - padding: 0; - font-family: sans-serif; -} +// #endregion form.semanticForms { - color: var(--formTextColor); width: 100%; + // style reset + * { + color: var(--formTextColor); + box-sizing: border-box; + font-family: sans-serif; + margin: 0; + padding: 0; + } + + // #region container layout fieldset { display: flex; flex-direction: column; - gap: 10px; - border-radius: var(--borderRadius); + gap: 5px; padding: 20px 10px; margin-bottom: 15px; + border-radius: var(--borderRadius); background: var(--formSubBackgroundColor); border: 1px var(--subBorderColor) solid; dl { display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); // allows grid items to automatically resize + // responsive layout for grid, re-fits once the --inputMinWidth is met, 1fr stretches to fill the space + grid-template-columns: repeat(auto-fit, minmax(var(--inputMinWidth), 1fr)); gap: 10px; margin-bottom: 10px; - dd:not(.checkboxes):not(.radios) { - display: flex; - gap: 10px; - max-width: 500px; // prevents inputs from spanning entire width + dd { + position: relative; - &:not(.singleCheckbox) { - flex-direction: column; + &:not(.checkboxes, .radios) { + display: flex; + gap: 10px; + // prevent inputs from spanning entire width when there are no following items + max-width: 500px; + + // places all items within the
    horizontally + &:not(.singleCheckbox) { + flex-direction: column; + } } - label { - cursor: pointer; + &.checkboxes ul, &.radios ul { + display: flex; + flex-direction: column; + margin-top: var(--inputTopMargin); + padding-left: 10px; + gap: 5px; } } } @@ -80,48 +95,23 @@ form.semanticForms { menu, ul { display: flex; justify-content: space-between; - padding: 5px; + flex-wrap: wrap; + gap: 10px; + // padding: 5px; list-style-type: none; } - // adjust checkbox and radios labels - dt { - position: relative; - - label[data-for="checkboxes"], - label[data-for="radios"] { - position: absolute; - transform: translateY(-100%) scale(0.8); - top: 10px; - } + details[open], summary { + margin-bottom: 10px; } + // #endregion - .checkboxes ul, - .radios ul { - padding-left: 10px; - margin-top: 5px; - display: flex; - flex-direction: column; - gap: 4px; - } - - dd { - position: relative; - } - - label { - user-select: none; - color: var(--placeholderColor); - touch-action: manipulation; - } - - // style all input types + // #region input styling input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), select, textarea { background: var(--formBackgroundColor); border: var(--border); - color: var(--formTextColor); width: 100%; border-radius: var(--borderRadius); font-size: 16px; @@ -161,9 +151,10 @@ form.semanticForms { input[type=checkbox], input[type=radio] { - // 30# times larger based on font size + // 30% larger based on font size width: 1.3em; height: 1.3em; + cursor: pointer; } // custom dropdown graphic on select element @@ -184,21 +175,16 @@ form.semanticForms { min-height: 38px; height: 100px; } + // #endregion - // update for scrollbars - @supports (scrollbar-color: auto) { - textarea { - scrollbar-color: var(--scrollbarColor) var(--formBackgroundColor); - } - } - - // "x" button that appears when a value is entered + // #region buttons button.clear { cursor: pointer; appearance: none; -webkit-appearance: none; position: absolute; - top: 10px; // account for margin above each input + height: min-content; + top: var(--inputTopMargin); // account for margin above each input bottom: 0; right: 0; margin: auto 6px; @@ -237,11 +223,10 @@ form.semanticForms { max-width: max-content; cursor: pointer; background-image: linear-gradient(to bottom, var(--buttonGradientLight) 0%, var(--buttonGradientDark) 100%); - color: var(--formTextColor); border: 2px var(--buttonGradientDark) solid; border-radius: 20px; padding: 5px 25px; - margin: 25px 10px; + // margin: 25px 10px; font-size: 100%; -webkit-appearance: none; -moz-appearance: none; @@ -257,38 +242,65 @@ form.semanticForms { background-image: linear-gradient(to bottom, var(--buttonGradientDark) 0%, var(--buttonGradientLight) 100%); } } + // #endregion - // style placeholders - input, - textarea { + // #region placeholders + input, textarea { &::placeholder { color: var(--placeholderColor); opacity: 1; } } - - input:not(:placeholder-shown) + label, - input:focus + label, - textarea:not(:placeholder-shown) + label, - textarea:focus + label, - select + label.floatLabelFormAnimatedLabel, - .checkboxes label.floatLabelFormAnimatedLabel, - .radios label.floatLabelFormAnimatedLabel, - dt > label { - color: var(--formTextColor); - } + // #endregion // animated labels .floatLabelForm { + container-type: inline-size; + div { position: relative; + width: 100%; + + // #region span classes + &.span-1, + &.span-2, + &.span-3, + &.span-4, + &.span-5 { + dd { + max-width: 100% !important; + } + } + + &.span-1 { + grid-column: span 1; + } + + &.span-2 { + grid-column: span 2; + } + + &.span-3 { + grid-column: span 3; + } + + &.span-4 { + grid-column: span 4; + } + + &.span-5 { + grid-column: span 5; + } + // #endregion - dd:not(.singleCheckbox):not(.checkboxes):not(.radios) { + + dd:not(.singleCheckbox, .checkboxes, .radios) { label { position: absolute; transform-origin: left center; pointer-events: none; - top: 20px; + // when the label is positioned within the input, it needs a 10px buffer + top: calc(var(--inputTopMargin) + 10px); left: 8px; transition: transform 250ms; cursor: text; @@ -300,7 +312,7 @@ form.semanticForms { input, textarea, select { - margin-top: 10px; + margin-top: var(--inputTopMargin); } input, @@ -346,6 +358,26 @@ form.semanticForms { } } } + + // #region labels + + // top level label for checkbox and radio groups + dt { + position: relative; + + label:is([data-for="checkboxes"], [data-for="radios"]) { + position: absolute; + transform: translateY(-100%) scale(0.8); + top: var(--inputTopMargin); + } + } + + label { + user-select: none; + color: var(--placeholderColor); + touch-action: manipulation; + } + // #endregion } // disable autofill yellow @@ -368,7 +400,14 @@ form.semanticForms { } } - // low flow specific styling + // update for scrollbars + @supports (scrollbar-color: auto) { + textarea { + scrollbar-color: var(--scrollbarColor) var(--formBackgroundColor); + } + } + + // #region low flow form &.lowFlow { fieldset { dl { @@ -382,5 +421,11 @@ form.semanticForms { margin-bottom: 10px; } } + + .checkboxes ul, + .radios ul { + margin-top: calc(var(--inputTopMargin) / 2); + } } + // #endregion } \ No newline at end of file From dee123841714e71df810425ae105609521f69dbd Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Thu, 5 Sep 2024 13:00:32 -0400 Subject: [PATCH 14/60] add container query --- semanticForms.css | 98 ++++++++++++++++++++------------- semanticForms.less | 132 +++++++++++++++++++++++++++------------------ 2 files changed, 141 insertions(+), 89 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index 81b4c79..bc293f8 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -43,6 +43,7 @@ form.semanticForms * { padding: 0; } form.semanticForms fieldset { + container-type: inline-size; display: flex; flex-direction: column; gap: 5px; @@ -223,35 +224,10 @@ form.semanticForms textarea::placeholder { color: var(--placeholderColor); opacity: 1; } -form.semanticForms .floatLabelForm { - container-type: inline-size; -} form.semanticForms .floatLabelForm div { position: relative; width: 100%; } -form.semanticForms .floatLabelForm div.span-1 dd, -form.semanticForms .floatLabelForm div.span-2 dd, -form.semanticForms .floatLabelForm div.span-3 dd, -form.semanticForms .floatLabelForm div.span-4 dd, -form.semanticForms .floatLabelForm div.span-5 dd { - max-width: 100% !important; -} -form.semanticForms .floatLabelForm div.span-1 { - grid-column: span 1; -} -form.semanticForms .floatLabelForm div.span-2 { - grid-column: span 2; -} -form.semanticForms .floatLabelForm div.span-3 { - grid-column: span 3; -} -form.semanticForms .floatLabelForm div.span-4 { - grid-column: span 4; -} -form.semanticForms .floatLabelForm div.span-5 { - grid-column: span 5; -} form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) label { position: absolute; transform-origin: left center; @@ -318,18 +294,40 @@ form.semanticForms .floatLabelForm div label { color: var(--placeholderColor); touch-action: manipulation; } -form.semanticForms .floatLabelForm input:-webkit-autofill, -form.semanticForms .floatLabelForm input:-webkit-autofill:hover, -form.semanticForms .floatLabelForm input:-webkit-autofill:focus, -form.semanticForms .floatLabelForm input:-webkit-autofill:active, -form.semanticForms .floatLabelForm textarea:-webkit-autofill, -form.semanticForms .floatLabelForm textarea:-webkit-autofill:hover, -form.semanticForms .floatLabelForm textarea:-webkit-autofill:focus, -form.semanticForms .floatLabelForm textarea:-webkit-autofill:active, -form.semanticForms .floatLabelForm select:-webkit-autofill, -form.semanticForms .floatLabelForm select:-webkit-autofill:hover, -form.semanticForms .floatLabelForm select:-webkit-autofill:focus, -form.semanticForms .floatLabelForm select:-webkit-autofill:active { +form.semanticForms .floatLabelForm div.span-1 dd, +form.semanticForms .floatLabelForm div.span-2 dd, +form.semanticForms .floatLabelForm div.span-3 dd, +form.semanticForms .floatLabelForm div.span-4 dd, +form.semanticForms .floatLabelForm div.span-5 dd { + max-width: 100% !important; +} +form.semanticForms .floatLabelForm div.span-1 { + grid-column: span 1; +} +form.semanticForms .floatLabelForm div.span-2 { + grid-column: span 2; +} +form.semanticForms .floatLabelForm div.span-3 { + grid-column: span 3; +} +form.semanticForms .floatLabelForm div.span-4 { + grid-column: span 4; +} +form.semanticForms .floatLabelForm div.span-5 { + grid-column: span 5; +} +form.semanticForms input:-webkit-autofill, +form.semanticForms input:-webkit-autofill:hover, +form.semanticForms input:-webkit-autofill:focus, +form.semanticForms input:-webkit-autofill:active, +form.semanticForms textarea:-webkit-autofill, +form.semanticForms textarea:-webkit-autofill:hover, +form.semanticForms textarea:-webkit-autofill:focus, +form.semanticForms textarea:-webkit-autofill:active, +form.semanticForms select:-webkit-autofill, +form.semanticForms select:-webkit-autofill:hover, +form.semanticForms select:-webkit-autofill:focus, +form.semanticForms select:-webkit-autofill:active { -webkit-box-shadow: 0 0 0 1000px var(--formBackgroundColor) inset; transition: background-color 5000s ease-in-out 0s, color 5000s ease-in-out 0s; transition-delay: 5000s; @@ -340,6 +338,32 @@ form.semanticForms .floatLabelForm select:-webkit-autofill:active { scrollbar-color: var(--scrollbarColor) var(--formBackgroundColor); } } +@container (width < 1300px) { + form.semanticForms .span-5 { + grid-column: span 4 !important; + } +} +@container (width < 1050px) { + form.semanticForms .span-4, + form.semanticForms .span-5 { + grid-column: span 3 !important; + } +} +@container (width < 800px) { + form.semanticForms .span-3, + form.semanticForms .span-4, + form.semanticForms .span-5 { + grid-column: span 2 !important; + } +} +@container (width < 550px) { + form.semanticForms .span-2, + form.semanticForms .span-3, + form.semanticForms .span-4, + form.semanticForms .span-5 { + grid-column: span 1 !important; + } +} form.semanticForms.lowFlow fieldset dl { display: flex; flex-direction: column; diff --git a/semanticForms.less b/semanticForms.less index 4f0f6e9..16e5852 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -50,6 +50,7 @@ form.semanticForms { // #region container layout fieldset { + container-type: inline-size; display: flex; flex-direction: column; gap: 5px; @@ -255,45 +256,10 @@ form.semanticForms { // animated labels .floatLabelForm { - container-type: inline-size; - div { position: relative; width: 100%; - // #region span classes - &.span-1, - &.span-2, - &.span-3, - &.span-4, - &.span-5 { - dd { - max-width: 100% !important; - } - } - - &.span-1 { - grid-column: span 1; - } - - &.span-2 { - grid-column: span 2; - } - - &.span-3 { - grid-column: span 3; - } - - &.span-4 { - grid-column: span 4; - } - - &.span-5 { - grid-column: span 5; - } - // #endregion - - dd:not(.singleCheckbox, .checkboxes, .radios) { label { position: absolute; @@ -380,24 +346,58 @@ form.semanticForms { // #endregion } - // disable autofill yellow - input:-webkit-autofill, - input:-webkit-autofill:hover, - input:-webkit-autofill:focus, - input:-webkit-autofill:active, - textarea:-webkit-autofill, - textarea:-webkit-autofill:hover, - textarea:-webkit-autofill:focus, - textarea:-webkit-autofill:active, - select:-webkit-autofill, - select:-webkit-autofill:hover, - select:-webkit-autofill:focus, - select:-webkit-autofill:active { - -webkit-box-shadow: 0 0 0 1000px var(--formBackgroundColor) inset; - transition: background-color 5000s ease-in-out 0s, color 5000s ease-in-out 0s; - transition-delay: 5000s; - transition-property: background-color, color; + // #region span classes + div { + &.span-1, + &.span-2, + &.span-3, + &.span-4, + &.span-5 { + dd { + max-width: 100% !important; + } + } + + &.span-1 { + grid-column: span 1; + } + + &.span-2 { + grid-column: span 2; + } + + &.span-3 { + grid-column: span 3; + } + + &.span-4 { + grid-column: span 4; + } + + &.span-5 { + grid-column: span 5; + } } + // #endregion + } + + // disable autofill yellow + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + input:-webkit-autofill:active, + textarea:-webkit-autofill, + textarea:-webkit-autofill:hover, + textarea:-webkit-autofill:focus, + textarea:-webkit-autofill:active, + select:-webkit-autofill, + select:-webkit-autofill:hover, + select:-webkit-autofill:focus, + select:-webkit-autofill:active { + -webkit-box-shadow: 0 0 0 1000px var(--formBackgroundColor) inset; + transition: background-color 5000s ease-in-out 0s, color 5000s ease-in-out 0s; + transition-delay: 5000s; + transition-property: background-color, color; } // update for scrollbars @@ -407,6 +407,34 @@ form.semanticForms { } } + + // #region container queries + @container (width < 1300px) { + .span-5 { + grid-column: span 4 !important; + } + } + + @container (width < 1050px) { + .span-4, .span-5 { + grid-column: span 3 !important; + } + } + + @container (width < 800px) { + .span-3, .span-4, .span-5 { + grid-column: span 2 !important; + } + } + + @container (width < 550px) { + .span-2, .span-3, .span-4, .span-5 { + grid-column: span 1 !important; + } + } + // #endregion + + // #region low flow form &.lowFlow { fieldset { From d1f8463f34de6671c97b77f0c428f17486e6fea9 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Thu, 5 Sep 2024 13:29:21 -0400 Subject: [PATCH 15/60] comment cleanup --- CHANGELOG.md | 2 +- semanticForms.html | 60 ++++++++++++++++++++++++++++++++++++++++++++-- semanticForms.js | 44 ++++++++++++++++++---------------- 3 files changed, 82 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 797e474..a930ed2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ - Fieldset elements now utilize CSS grid to dynamically fill available space before wrapping to the next row. - Input clear button is now a button element, allowing interaction via tab. - Input clear button avoids overlap with scrollbars on textarea elements. - - Added multiple utility classes that define how wide inputs will span. + - Added multiple utility classes that define how wide inputs will span in the responsive layout. ## 3.2.1 diff --git a/semanticForms.html b/semanticForms.html index 8ea13d3..47ddbbc 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -129,14 +129,70 @@

    Semantic Forms

    Nested fieldset
    -
    +
    - +

    Here is some subtext.

    + +
    +
    + +

    Here's some small subtext.

    +
    + +
    +
    + +

    Here's some bold subtext.

    +
    + +
    +
    + +

    Here is some subtext.

    +

    Here is some more subtext.

    +
    + +
    + Another nested fieldset + +
    +
    +
    + +
    +
    +
    +
    + Detail element + +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    + Another detail element +
    +
    +
    +
    +
    + diff --git a/semanticForms.js b/semanticForms.js index c84bee0..2165538 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -20,23 +20,22 @@ window.semanticForms = () => { const type = input.getAttribute('type') if (nodeNameLookup.includes(input.nodeName) || inputTypeLookup.includes(type)) { - // find
    element + // recursively find
    element let dl = input.parentNode while (dl && dl.nodeName !== 'DL') dl = dl.parentNode + if (!dl) continue if (!dl.classList.contains('floatLabelForm')) dl.classList.add('floatLabelForm') - let label - if (input.parentNode.parentNode.id && (type === 'checkbox' || type === 'radio')) { - label = document.querySelector('label[data-for=' + input.parentNode.parentNode.id.replace(/\./g, '\\.') + ']') - } else { - label = document.querySelector('label[for=' + input.id.replace(/\./g, '\\.') + ']') - } + const label = input.parentNode.parentNode.id && (type === 'checkbox' || type === 'radio') + ? document.querySelector('label[data-for=' + input.parentNode.parentNode.id.replace(/\./g, '\\.') + ']') + : document.querySelector('label[for=' + input.id.replace(/\./g, '\\.') + ']') input.classList.add('semanticform') - // specific handling of checkboxes and radios + // #region create labels if (type === 'checkbox' || type === 'radio') { + // recursively find
    element let dd = input.parentNode while (dd && dd.nodeName !== 'DD') dd = dd.parentNode @@ -52,17 +51,13 @@ window.semanticForms = () => { } newLabel.innerHTML = label.innerHTML - if (!dd.querySelector('label')) { - dd.append(newLabel) - } + if (!dd.querySelector('label')) dd.append(newLabel) } - const div = document.createElement('div') // removes old div that a radio or checkbox may have been added to - if (dd.parentElement.nodeName === 'DIV') { - dd.parentElement.remove() - } + if (dd.parentElement.nodeName === 'DIV') dd.parentElement.remove() + const div = document.createElement('div') div.append(label.closest('dt'), dd) dl.append(div) } else { @@ -73,6 +68,7 @@ window.semanticForms = () => { label.setAttribute('hidden', 'hidden') insertAfter(newLabel, input) } + // #endregion // standard inputs if (type !== 'checkbox' && type !== 'radio') { @@ -84,6 +80,7 @@ window.semanticForms = () => { const dt = label.closest('dt') const dd = input.closest('dd') + // #region clear button if (input.nodeName !== 'SELECT' && type !== 'range') { const clearBtn = document.createElement('button') clearBtn.type = 'button' @@ -96,7 +93,9 @@ window.semanticForms = () => { }) insertAfter(clearBtn, dd.querySelector('label')) } + // #endregion + // check for span utility class if (/span-/.test(dd.className)) { const match = dd.className.match(/span-[0-9]/)[0] dd.classList.remove(match) @@ -105,12 +104,12 @@ window.semanticForms = () => { div.append(dt, dd) dl.append(div) - if (dt.style.display === 'none' && dd.style.display === 'none') { - div.style.display = 'none' - } + + // determine visibility of newly created
    + if (dt.style.display === 'none' && dd.style.display === 'none') div.style.display = 'none' } - // handle file input clear btn - cannot be handled with CSS + // handle file input clear btn, cannot be handled with CSS if (type === 'file') { const clearBtn = input.parentElement.querySelector('.clear') input.addEventListener('input', e => { @@ -121,7 +120,6 @@ window.semanticForms = () => { }) } - // TODO investigate appending the button via DOM manipulation // add listener to shift clear button when scrollbar present for (const textarea of document.querySelectorAll('textarea')) { // shifts the close button to the right if a scrollbar is present @@ -139,7 +137,11 @@ window.semanticForms = () => { } } - // utility method for inserting an element after another element + /** + * Places an element immediately after another element + * @param {Object} newNode element being placed after the reference node + * @param {*} referenceNode element to be used as reference for new node + */ function insertAfter (newNode, referenceNode) { if (referenceNode.nextSibling) referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling) else referenceNode.parentNode.appendChild(newNode) From 07d9f69fc461c324a370f4cd73c023b3a2b4d970 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Mon, 9 Sep 2024 09:54:44 -0400 Subject: [PATCH 16/60] updates to low flow --- semanticForms.css | 12 ++++++++- semanticForms.html | 66 +++++++++++++++++++++++++++++++++++++++++----- semanticForms.less | 21 +++++++++++++-- 3 files changed, 90 insertions(+), 9 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index bc293f8..bdf4d79 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -90,6 +90,9 @@ form.semanticForms details[open], form.semanticForms summary { margin-bottom: 10px; } +form.semanticForms summary { + cursor: pointer; +} form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), form.semanticForms select, form.semanticForms textarea { @@ -370,9 +373,16 @@ form.semanticForms.lowFlow fieldset dl { gap: 5px; } form.semanticForms.lowFlow fieldset dd { - flex-direction: row !important; margin-bottom: 10px; } +form.semanticForms.lowFlow fieldset dd:not(.checkboxes) input[type="checkbox"] { + margin-left: 10px; +} +form.semanticForms.lowFlow fieldset dd input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type="range"]), +form.semanticForms.lowFlow fieldset dd select, +form.semanticForms.lowFlow fieldset dd textarea { + padding-right: 6px; +} form.semanticForms.lowFlow .checkboxes ul, form.semanticForms.lowFlow .radios ul { margin-top: calc(var(--inputTopMargin) / 2); diff --git a/semanticForms.html b/semanticForms.html index 47ddbbc..439f428 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -147,9 +147,9 @@

    Semantic Forms

    Here's some bold subtext.

    -
    +
    - +

    Here is some subtext.

    Here is some more subtext.

    @@ -161,7 +161,7 @@

    Semantic Forms

    - +
    @@ -169,7 +169,6 @@

    Semantic Forms

    Detail element -
    @@ -309,14 +308,69 @@

    Semantic Forms

    Nested fieldset
    -
    +
    - +

    Here is some subtext.

    + +
    +
    + +

    Here's some small subtext.

    +
    + +
    +
    + +

    Here's some bold subtext.

    +
    + +
    +
    + +

    Here is some subtext.

    +

    Here is some more subtext.

    +
    + +
    + Another nested fieldset + +
    +
    +
    + +
    +
    +
    +
    + Detail element +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    + Another detail element +
    +
    +
    +
    +
    + diff --git a/semanticForms.less b/semanticForms.less index 16e5852..8744f2f 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -98,13 +98,16 @@ form.semanticForms { justify-content: space-between; flex-wrap: wrap; gap: 10px; - // padding: 5px; list-style-type: none; } details[open], summary { margin-bottom: 10px; } + + summary { + cursor: pointer; + } // #endregion // #region input styling @@ -445,8 +448,22 @@ form.semanticForms { } dd { - flex-direction: row !important; margin-bottom: 10px; + + // nudge single checkboxes to match checkbox groups + &:not(.checkboxes) { + input[type="checkbox"] { + margin-left: 10px; + } + } + + // remove "x" padding + input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type="range"]), + select, + textarea { + padding-right: 6px; + } + } } From a880273bef4146e9a8b8a15cd788ee881a64a3cc Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Mon, 9 Sep 2024 10:27:56 -0400 Subject: [PATCH 17/60] add span-full class, update README --- README.md | 43 ++++++++++++++++++++++++++++++++----------- semanticForms.css | 6 +++++- semanticForms.html | 27 +++++++++++++++++++++++++-- semanticForms.js | 2 +- semanticForms.less | 6 +++++- 5 files changed, 68 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index a8e9372..3c1e97c 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Overview of pattern library features: ## Float label inputs -The float label input pattern is notoriously difficult to implement in a fashion that doesn't degrade HTML semantics or accessibility. This pattern library implements a solution that solves that problem. Your label doesn't need to be a sibling of your input like with other implementations. This implementation also has a custom clear field driven by SVG embedded in the CSS. +The float label input pattern is notoriously difficult to implement in a fashion that doesn't degrade HTML semantics or accessibility. This pattern library implements a solution that solves that problem. Your label doesn't need to be a sibling of your input like with other implementations. This implementation also has a custom clear button for each input. ### Example @@ -52,26 +52,47 @@ The float label input pattern is notoriously difficult to implement in a fashion ``` -If you would like to manipulate the size of the area on the input field reserved for the click event of the clear field, apply one or both of the following `data-` attributes to your form: - -Adjust the horizontal offset of the clear field's click event click area (the default is 21): +### Specify input columns +You can specify the number of columns an input will span using the `span-#` class on the `
    ` element. The inputs are responsive and will shrink according to available space. ```html -
    - + +
    + +
    +
    + + +
    +
    + + +
    +
    +
    ``` -Adjust the vertical offset of the clear field's click event click area (the default is 5): +`span-full` can also be used to force an input to take up the entire width of a form. ```html -
    - + +
    + +
    +
    + + +
    +
    + + +
    +
    +
    ``` -If you want to double the width of the input field (on screens with the extra space), add a `x2` class to the `dd` element. - ## Button groups You can align buttons side-by-side, or in left/right/center groups. diff --git a/semanticForms.css b/semanticForms.css index bdf4d79..79d2627 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -301,7 +301,8 @@ form.semanticForms .floatLabelForm div.span-1 dd, form.semanticForms .floatLabelForm div.span-2 dd, form.semanticForms .floatLabelForm div.span-3 dd, form.semanticForms .floatLabelForm div.span-4 dd, -form.semanticForms .floatLabelForm div.span-5 dd { +form.semanticForms .floatLabelForm div.span-5 dd, +form.semanticForms .floatLabelForm div.span-full dd { max-width: 100% !important; } form.semanticForms .floatLabelForm div.span-1 { @@ -319,6 +320,9 @@ form.semanticForms .floatLabelForm div.span-4 { form.semanticForms .floatLabelForm div.span-5 { grid-column: span 5; } +form.semanticForms .floatLabelForm div.span-full { + grid-column: 1 / -1; +} form.semanticForms input:-webkit-autofill, form.semanticForms input:-webkit-autofill:hover, form.semanticForms input:-webkit-autofill:focus, diff --git a/semanticForms.html b/semanticForms.html index 439f428..6ba666d 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -104,7 +104,7 @@

    Semantic Forms

    -
    +
    @@ -122,7 +122,7 @@

    Semantic Forms

    -
    +
    @@ -167,6 +167,29 @@

    Semantic Forms

    +
    + Span classes + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    Detail element
    diff --git a/semanticForms.js b/semanticForms.js index 2165538..3f80802 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -97,7 +97,7 @@ window.semanticForms = () => { // check for span utility class if (/span-/.test(dd.className)) { - const match = dd.className.match(/span-[0-9]/)[0] + const match = dd.className.match(/span-([0-9]|full)/)[0] dd.classList.remove(match) div.classList.add(match) } diff --git a/semanticForms.less b/semanticForms.less index 8744f2f..69e50d2 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -355,7 +355,8 @@ form.semanticForms { &.span-2, &.span-3, &.span-4, - &.span-5 { + &.span-5, + &.span-full { dd { max-width: 100% !important; } @@ -380,6 +381,9 @@ form.semanticForms { &.span-5 { grid-column: span 5; } + &.span-full { + grid-column: 1 / -1; + } } // #endregion } From 595b962ca7eecace26dc1e61548be9ec4709a2b0 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Mon, 9 Sep 2024 13:34:55 -0400 Subject: [PATCH 18/60] tweaks to match original version --- README.md | 14 +++---- package.json | 2 +- semanticForms.css | 100 +++++++++++++++++++++++++++----------------- semanticForms.html | 34 +++++++-------- semanticForms.js | 8 ++-- semanticForms.less | 102 ++++++++++++++++++++++++++++----------------- 6 files changed, 155 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index 3c1e97c..b158d2a 100644 --- a/README.md +++ b/README.md @@ -53,38 +53,38 @@ The float label input pattern is notoriously difficult to implement in a fashion ``` ### Specify input columns -You can specify the number of columns an input will span using the `span-#` class on the `
    ` element. The inputs are responsive and will shrink according to available space. +You can specify the number of columns an input will span using the `col-#` class on the `
    ` element. The inputs are responsive and will shrink according to available space. ```html
    -
    +
    -
    +
    -
    +
    ``` -`span-full` can also be used to force an input to take up the entire width of a form. +`col-full` can also be used to force an input to take up the entire width of a form. ```html
    -
    +
    -
    +
    diff --git a/package.json b/package.json index 27b93e5..cbe58d9 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,9 @@ "main": "semanticForms.js", "readmeFilename": "README.md", "devDependencies": { - "less": "4.2.0", "eslint": "9.9.1", "eslint-plugin-html": "8.1.1", + "less": "4.2.0", "standard": "17.1.0" }, "scripts": { diff --git a/semanticForms.css b/semanticForms.css index 79d2627..b598060 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -78,6 +78,16 @@ form.semanticForms fieldset dl dd.radios ul { padding-left: 10px; gap: 5px; } +form.semanticForms fieldset dl dd.checkboxes ul li, +form.semanticForms fieldset dl dd.radios ul li { + display: flex; + align-items: center; + gap: 5px; +} +form.semanticForms fieldset dl dd.checkboxes ul li label, +form.semanticForms fieldset dl dd.radios ul li label { + margin-top: 2px; +} form.semanticForms menu, form.semanticForms ul { display: flex; @@ -102,12 +112,12 @@ form.semanticForms textarea { border-radius: var(--borderRadius); font-size: 16px; touch-action: manipulation; + outline: none; } form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type="range"]), form.semanticForms select:not([type="range"]), form.semanticForms textarea:not([type="range"]) { - padding: 6px; - padding-right: 30px; + padding: 6px 30px 6px 20px; } form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio])[disabled], form.semanticForms select[disabled], @@ -120,13 +130,20 @@ form.semanticForms select[disabled] + label, form.semanticForms textarea[disabled] + label { filter: brightness(50%); } -form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):focus + label, -form.semanticForms select:focus + label, -form.semanticForms textarea:focus + label, -form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not(:placeholder-shown) + label, -form.semanticForms select:not(:placeholder-shown) + label, -form.semanticForms textarea:not(:placeholder-shown) + label { - transform: translateY(-150%) scale(0.75); +form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):focus, +form.semanticForms select:focus, +form.semanticForms textarea:focus { + outline: none; + box-shadow: 0 0 0 2px var(--borderColor); +} +form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):focus:not([type=checkbox]):not([type=radio]) + label, +form.semanticForms select:focus:not([type=checkbox]):not([type=radio]) + label, +form.semanticForms textarea:focus:not([type=checkbox]):not([type=radio]) + label, +form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not(:placeholder-shown):not([type=checkbox]):not([type=radio]) + label, +form.semanticForms select:not(:placeholder-shown):not([type=checkbox]):not([type=radio]) + label, +form.semanticForms textarea:not(:placeholder-shown):not([type=checkbox]):not([type=radio]) + label { + color: var(--formTextColor); + transform: translateY(-150%) scale(0.7); } form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), form.semanticForms select { @@ -143,6 +160,10 @@ form.semanticForms input[type=radio] { height: 1.3em; cursor: pointer; } +form.semanticForms input[type=checkbox] + label, +form.semanticForms input[type=radio] + label { + color: var(--formTextColor) !important; +} form.semanticForms select { cursor: pointer; background-image: var(--selectIcon); @@ -168,6 +189,8 @@ form.semanticForms button.clear { top: var(--inputTopMargin); bottom: 0; right: 0; + width: 25px; + height: 25px; margin: auto 6px; padding: 5px; background: none; @@ -222,21 +245,17 @@ form.semanticForms input[type='image']:focus, form.semanticForms button:not(.clear):focus { background-image: linear-gradient(to bottom, var(--buttonGradientDark) 0%, var(--buttonGradientLight) 100%); } -form.semanticForms input::placeholder, -form.semanticForms textarea::placeholder { - color: var(--placeholderColor); - opacity: 1; -} form.semanticForms .floatLabelForm div { position: relative; width: 100%; } form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) label { + font-size: 18px; position: absolute; transform-origin: left center; pointer-events: none; - top: calc(var(--inputTopMargin) + 10px); - left: 8px; + top: calc(var(--inputTopMargin) + 8px); + left: 20px; transition: transform 250ms; cursor: text; white-space: nowrap; @@ -297,30 +316,35 @@ form.semanticForms .floatLabelForm div label { color: var(--placeholderColor); touch-action: manipulation; } -form.semanticForms .floatLabelForm div.span-1 dd, -form.semanticForms .floatLabelForm div.span-2 dd, -form.semanticForms .floatLabelForm div.span-3 dd, -form.semanticForms .floatLabelForm div.span-4 dd, -form.semanticForms .floatLabelForm div.span-5 dd, -form.semanticForms .floatLabelForm div.span-full dd { +form.semanticForms .floatLabelForm input::placeholder, +form.semanticForms .floatLabelForm textarea::placeholder { + color: var(--placeholderColor); + opacity: 1; +} +form.semanticForms .floatLabelForm div.col-1 dd, +form.semanticForms .floatLabelForm div.col-2 dd, +form.semanticForms .floatLabelForm div.col-3 dd, +form.semanticForms .floatLabelForm div.col-4 dd, +form.semanticForms .floatLabelForm div.col-5 dd, +form.semanticForms .floatLabelForm div.col-full dd { max-width: 100% !important; } -form.semanticForms .floatLabelForm div.span-1 { +form.semanticForms .floatLabelForm div.col-1 { grid-column: span 1; } -form.semanticForms .floatLabelForm div.span-2 { +form.semanticForms .floatLabelForm div.col-2 { grid-column: span 2; } -form.semanticForms .floatLabelForm div.span-3 { +form.semanticForms .floatLabelForm div.col-3 { grid-column: span 3; } -form.semanticForms .floatLabelForm div.span-4 { +form.semanticForms .floatLabelForm div.col-4 { grid-column: span 4; } -form.semanticForms .floatLabelForm div.span-5 { +form.semanticForms .floatLabelForm div.col-5 { grid-column: span 5; } -form.semanticForms .floatLabelForm div.span-full { +form.semanticForms .floatLabelForm div.col-full { grid-column: 1 / -1; } form.semanticForms input:-webkit-autofill, @@ -346,28 +370,28 @@ form.semanticForms select:-webkit-autofill:active { } } @container (width < 1300px) { - form.semanticForms .span-5 { + form.semanticForms .col-5 { grid-column: span 4 !important; } } @container (width < 1050px) { - form.semanticForms .span-4, - form.semanticForms .span-5 { + form.semanticForms .col-4, + form.semanticForms .col-5 { grid-column: span 3 !important; } } @container (width < 800px) { - form.semanticForms .span-3, - form.semanticForms .span-4, - form.semanticForms .span-5 { + form.semanticForms .col-3, + form.semanticForms .col-4, + form.semanticForms .col-5 { grid-column: span 2 !important; } } @container (width < 550px) { - form.semanticForms .span-2, - form.semanticForms .span-3, - form.semanticForms .span-4, - form.semanticForms .span-5 { + form.semanticForms .col-2, + form.semanticForms .col-3, + form.semanticForms .col-4, + form.semanticForms .col-5 { grid-column: span 1 !important; } } diff --git a/semanticForms.html b/semanticForms.html index 6ba666d..8cb7f51 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -168,25 +168,25 @@

    Semantic Forms

    - Span classes + Col classes
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    diff --git a/semanticForms.js b/semanticForms.js index 3f80802..d110431 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -85,7 +85,7 @@ window.semanticForms = () => { const clearBtn = document.createElement('button') clearBtn.type = 'button' clearBtn.ariaLabel = 'Clear input' - clearBtn.innerHTML = '' + clearBtn.innerHTML = '' clearBtn.classList.add('clear') clearBtn.addEventListener('click', () => { input.value = '' @@ -95,9 +95,9 @@ window.semanticForms = () => { } // #endregion - // check for span utility class - if (/span-/.test(dd.className)) { - const match = dd.className.match(/span-([0-9]|full)/)[0] + // check for col- utility class + if (/col-/.test(dd.className)) { + const match = dd.className.match(/col-([0-9]|full)/)[0] dd.classList.remove(match) div.classList.add(match) } diff --git a/semanticForms.less b/semanticForms.less index 69e50d2..0ea0555 100644 --- a/semanticForms.less +++ b/semanticForms.less @@ -88,6 +88,17 @@ form.semanticForms { margin-top: var(--inputTopMargin); padding-left: 10px; gap: 5px; + + li { + display: flex; + align-items: center; + gap: 5px; + + label { + // shift text down to match center + margin-top: 2px; + } + } } } } @@ -120,10 +131,10 @@ form.semanticForms { border-radius: var(--borderRadius); font-size: 16px; touch-action: manipulation; + outline: none; &:not([type="range"]) { - padding: 6px; - padding-right: 30px; + padding: 6px 30px 6px 20px; } &[disabled] { @@ -134,10 +145,22 @@ form.semanticForms { filter: brightness(50%); } } + } - &:focus + label, - &:not(:placeholder-shown)+label { - transform: translateY(-150%) scale(0.75); + // focus attributes + input:not([type='submit']):not([type='reset']):not([type='image']), + select, + textarea { + // custom focus highlight + &:focus { + outline: none; + box-shadow: 0 0 0 2px var(--borderColor); + } + + &:focus:not([type=checkbox]):not([type=radio]) + label, + &:not(:placeholder-shown):not([type=checkbox]):not([type=radio])+label { + color: var(--formTextColor); + transform: translateY(-150%) scale(0.7); } } @@ -159,6 +182,10 @@ form.semanticForms { width: 1.3em; height: 1.3em; cursor: pointer; + + & + label { + color: var(--formTextColor) !important; + } } // custom dropdown graphic on select element @@ -191,6 +218,8 @@ form.semanticForms { top: var(--inputTopMargin); // account for margin above each input bottom: 0; right: 0; + width: 25px; + height: 25px; margin: auto 6px; padding: 5px; background: none; @@ -248,16 +277,7 @@ form.semanticForms { } // #endregion - // #region placeholders - input, textarea { - &::placeholder { - color: var(--placeholderColor); - opacity: 1; - } - } - // #endregion - - // animated labels + // #region labels .floatLabelForm { div { position: relative; @@ -265,12 +285,13 @@ form.semanticForms { dd:not(.singleCheckbox, .checkboxes, .radios) { label { + font-size: 18px; position: absolute; transform-origin: left center; pointer-events: none; - // when the label is positioned within the input, it needs a 10px buffer - top: calc(var(--inputTopMargin) + 10px); - left: 8px; + // when the label is positioned within the input it needs a buffer + top: calc(var(--inputTopMargin) + 8px); + left: 20px; transition: transform 250ms; cursor: text; white-space: nowrap; @@ -328,8 +349,6 @@ form.semanticForms { } } - // #region labels - // top level label for checkbox and radio groups dt { position: relative; @@ -346,42 +365,49 @@ form.semanticForms { color: var(--placeholderColor); touch-action: manipulation; } - // #endregion } - // #region span classes + input, textarea { + &::placeholder { + color: var(--placeholderColor); + opacity: 1; + } + } + // #endregion + + // #region col classes div { - &.span-1, - &.span-2, - &.span-3, - &.span-4, - &.span-5, - &.span-full { + &.col-1, + &.col-2, + &.col-3, + &.col-4, + &.col-5, + &.col-full { dd { max-width: 100% !important; } } - &.span-1 { + &.col-1 { grid-column: span 1; } - &.span-2 { + &.col-2 { grid-column: span 2; } - &.span-3 { + &.col-3 { grid-column: span 3; } - &.span-4 { + &.col-4 { grid-column: span 4; } - &.span-5 { + &.col-5 { grid-column: span 5; } - &.span-full { + &.col-full { grid-column: 1 / -1; } } @@ -417,25 +443,25 @@ form.semanticForms { // #region container queries @container (width < 1300px) { - .span-5 { + .col-5 { grid-column: span 4 !important; } } @container (width < 1050px) { - .span-4, .span-5 { + .col-4, .col-5 { grid-column: span 3 !important; } } @container (width < 800px) { - .span-3, .span-4, .span-5 { + .col-3, .col-4, .col-5 { grid-column: span 2 !important; } } @container (width < 550px) { - .span-2, .span-3, .span-4, .span-5 { + .col-2, .col-3, .col-4, .col-5 { grid-column: span 1 !important; } } From 8e560078eed9c5bd617b900f3060254be2d274d1 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Mon, 9 Sep 2024 13:39:14 -0400 Subject: [PATCH 19/60] switch to sass --- package-lock.json | 368 ++++++++++++----------- package.json | 5 +- semanticForms.css | 96 +++--- semanticForms.css.map | 1 + semanticForms.less => semanticForms.scss | 0 5 files changed, 243 insertions(+), 227 deletions(-) create mode 100644 semanticForms.css.map rename semanticForms.less => semanticForms.scss (100%) diff --git a/package-lock.json b/package-lock.json index cbcfb10..ef56318 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "devDependencies": { "eslint": "9.9.1", "eslint-plugin-html": "8.1.1", - "less": "4.2.0", + "sass": "1.78.0", "standard": "17.1.0" }, "funding": { @@ -268,6 +268,20 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -457,6 +471,19 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -467,6 +494,19 @@ "concat-map": "0.0.1" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/builtins": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", @@ -532,6 +572,44 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -556,18 +634,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/copy-anything": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", - "dev": true, - "dependencies": { - "is-what": "^3.14.1" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -769,19 +835,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "dev": true, - "optional": true, - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1329,6 +1382,19 @@ "node": ">=16.0.0" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -1379,6 +1445,21 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -1648,19 +1729,6 @@ "entities": "^4.5.0" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -1670,18 +1738,12 @@ "node": ">= 4" } }, - "node_modules/image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "node_modules/immutable": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", "dev": true, - "optional": true, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -1788,6 +1850,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -1930,6 +2005,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-number-object": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", @@ -2082,12 +2167,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-what": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true - }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -2191,32 +2270,6 @@ "json-buffer": "3.0.1" } }, - "node_modules/less": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", - "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", - "dev": true, - "dependencies": { - "copy-anything": "^2.0.1", - "parse-node-version": "^1.0.1", - "tslib": "^2.3.0" - }, - "bin": { - "lessc": "bin/lessc" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "make-dir": "^2.1.0", - "mime": "^1.4.1", - "needle": "^3.1.0", - "source-map": "~0.6.0" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2279,33 +2332,6 @@ "loose-envify": "cli.js" } }, - "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "optional": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "optional": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2339,21 +2365,14 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/needle": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", - "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.3", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, + "license": "MIT", "engines": { - "node": ">= 4.4.x" + "node": ">=0.10.0" } }, "node_modules/object-assign": { @@ -2571,15 +2590,6 @@ "node": ">=4" } }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2613,6 +2623,19 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -2725,13 +2748,6 @@ "react-is": "^16.13.1" } }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", - "dev": true, - "optional": true - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -2767,6 +2783,19 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", @@ -2928,28 +2957,22 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "optional": true - }, - "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "node_modules/sass": { + "version": "1.78.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.78.0.tgz", + "integrity": "sha512-AaIqGSrjo5lA2Yg7RvFZrlXDBCp3nV4XP73GrLGvdRWWwk+8H3l0SDvq/5bA4eF+0RFPLuWUk3E+P1U/YqnpsQ==", "dev": true, - "optional": true - }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "optional": true, + "license": "MIT", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, "bin": { - "semver": "bin/semver" + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" } }, "node_modules/set-function-length": { @@ -3023,12 +3046,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, - "optional": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -3597,6 +3620,19 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -3609,12 +3645,6 @@ "strip-bom": "^3.0.0" } }, - "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index cbe58d9..91e5072 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "devDependencies": { "eslint": "9.9.1", "eslint-plugin-html": "8.1.1", - "less": "4.2.0", + "sass": "1.78.0", "standard": "17.1.0" }, "scripts": { @@ -23,7 +23,8 @@ "coverage": "echo \"TODO: test coverage\"", "lint": "standard && standard --plugin html *.html", "lint-fix": "standard --fix && standard --plugin html *.html --fix", - "build": "lessc semanticForms.less semanticForms.css" + "build": "sass semanticForms.scss semanticForms.css", + "watch": "sass --watch semanticForms.scss semanticForms.css" }, "repository": { "type": "git", diff --git a/semanticForms.css b/semanticForms.css index b598060..312eec3 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -17,6 +17,7 @@ form.semanticForms { --inputTopMargin: 15px; --inputMinWidth: 250px; } + form.semanticForms.dark { --formBackgroundColor: #555; --formSubBackgroundColor: #2f2f2f; @@ -32,6 +33,7 @@ form.semanticForms.dark { --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); --border: none; } + form.semanticForms { width: 100%; } @@ -70,40 +72,35 @@ form.semanticForms fieldset dl dd:not(.checkboxes, .radios) { form.semanticForms fieldset dl dd:not(.checkboxes, .radios):not(.singleCheckbox) { flex-direction: column; } -form.semanticForms fieldset dl dd.checkboxes ul, -form.semanticForms fieldset dl dd.radios ul { +form.semanticForms fieldset dl dd.checkboxes ul, form.semanticForms fieldset dl dd.radios ul { display: flex; flex-direction: column; margin-top: var(--inputTopMargin); padding-left: 10px; gap: 5px; } -form.semanticForms fieldset dl dd.checkboxes ul li, -form.semanticForms fieldset dl dd.radios ul li { +form.semanticForms fieldset dl dd.checkboxes ul li, form.semanticForms fieldset dl dd.radios ul li { display: flex; align-items: center; gap: 5px; } -form.semanticForms fieldset dl dd.checkboxes ul li label, -form.semanticForms fieldset dl dd.radios ul li label { +form.semanticForms fieldset dl dd.checkboxes ul li label, form.semanticForms fieldset dl dd.radios ul li label { margin-top: 2px; } -form.semanticForms menu, -form.semanticForms ul { +form.semanticForms menu, form.semanticForms ul { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 10px; list-style-type: none; } -form.semanticForms details[open], -form.semanticForms summary { +form.semanticForms details[open], form.semanticForms summary { margin-bottom: 10px; } form.semanticForms summary { cursor: pointer; } -form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), +form.semanticForms input:not([type=submit]):not([type=reset]):not([type=image]):not([type=checkbox]):not([type=radio]), form.semanticForms select, form.semanticForms textarea { background: var(--formBackgroundColor); @@ -114,38 +111,37 @@ form.semanticForms textarea { touch-action: manipulation; outline: none; } -form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type="range"]), -form.semanticForms select:not([type="range"]), -form.semanticForms textarea:not([type="range"]) { +form.semanticForms input:not([type=submit]):not([type=reset]):not([type=image]):not([type=checkbox]):not([type=radio]):not([type=range]), +form.semanticForms select:not([type=range]), +form.semanticForms textarea:not([type=range]) { padding: 6px 30px 6px 20px; } -form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio])[disabled], +form.semanticForms input:not([type=submit]):not([type=reset]):not([type=image]):not([type=checkbox]):not([type=radio])[disabled], form.semanticForms select[disabled], form.semanticForms textarea[disabled] { cursor: not-allowed; opacity: 0.5; } -form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio])[disabled] + label, +form.semanticForms input:not([type=submit]):not([type=reset]):not([type=image]):not([type=checkbox]):not([type=radio])[disabled] + label, form.semanticForms select[disabled] + label, form.semanticForms textarea[disabled] + label { filter: brightness(50%); } -form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):focus, +form.semanticForms input:not([type=submit]):not([type=reset]):not([type=image]):focus, form.semanticForms select:focus, form.semanticForms textarea:focus { outline: none; box-shadow: 0 0 0 2px var(--borderColor); } -form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):focus:not([type=checkbox]):not([type=radio]) + label, +form.semanticForms input:not([type=submit]):not([type=reset]):not([type=image]):focus:not([type=checkbox]):not([type=radio]) + label, form.semanticForms input:not([type=submit]):not([type=reset]):not([type=image]):not(:placeholder-shown):not([type=checkbox]):not([type=radio]) + label, form.semanticForms select:focus:not([type=checkbox]):not([type=radio]) + label, -form.semanticForms textarea:focus:not([type=checkbox]):not([type=radio]) + label, -form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not(:placeholder-shown):not([type=checkbox]):not([type=radio]) + label, form.semanticForms select:not(:placeholder-shown):not([type=checkbox]):not([type=radio]) + label, +form.semanticForms textarea:focus:not([type=checkbox]):not([type=radio]) + label, form.semanticForms textarea:not(:placeholder-shown):not([type=checkbox]):not([type=radio]) + label { color: var(--formTextColor); transform: translateY(-150%) scale(0.7); } -form.semanticForms input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]), +form.semanticForms input:not([type=submit]):not([type=reset]):not([type=image]):not([type=checkbox]):not([type=radio]), form.semanticForms select { height: var(--inputHeight); } @@ -200,8 +196,7 @@ form.semanticForms button.clear { align-items: center; justify-content: center; } -form.semanticForms button.clear:hover, -form.semanticForms button.clear:focus { +form.semanticForms button.clear:hover, form.semanticForms button.clear:focus { filter: brightness(0.8); } form.semanticForms textarea + label + .clear { @@ -213,9 +208,9 @@ form.semanticForms textarea:placeholder-shown + label + .clear, form.semanticForms input[type=file] + label + .clear { display: none; } -form.semanticForms input[type='submit'], -form.semanticForms input[type='reset'], -form.semanticForms input[type='image'], +form.semanticForms input[type=submit], +form.semanticForms input[type=reset], +form.semanticForms input[type=image], form.semanticForms button:not(.clear) { max-width: max-content; cursor: pointer; @@ -229,19 +224,18 @@ form.semanticForms button:not(.clear) { appearance: none; transition: filter 0.1s; } -form.semanticForms input[type='submit']:hover, -form.semanticForms input[type='reset']:hover, -form.semanticForms input[type='image']:hover, +form.semanticForms input[type=submit]:hover, +form.semanticForms input[type=reset]:hover, +form.semanticForms input[type=image]:hover, form.semanticForms button:not(.clear):hover { filter: brightness(1.2); } -form.semanticForms input[type='submit']:active, -form.semanticForms input[type='reset']:active, -form.semanticForms input[type='image']:active, +form.semanticForms input[type=submit]:active, form.semanticForms input[type=submit]:focus, +form.semanticForms input[type=reset]:active, +form.semanticForms input[type=reset]:focus, +form.semanticForms input[type=image]:active, +form.semanticForms input[type=image]:focus, form.semanticForms button:not(.clear):active, -form.semanticForms input[type='submit']:focus, -form.semanticForms input[type='reset']:focus, -form.semanticForms input[type='image']:focus, form.semanticForms button:not(.clear):focus { background-image: linear-gradient(to bottom, var(--buttonGradientDark) 0%, var(--buttonGradientLight) 100%); } @@ -306,7 +300,7 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .rad form.semanticForms .floatLabelForm div dt { position: relative; } -form.semanticForms .floatLabelForm div dt label:is([data-for="checkboxes"], [data-for="radios"]) { +form.semanticForms .floatLabelForm div dt label:is([data-for=checkboxes], [data-for=radios]) { position: absolute; transform: translateY(-100%) scale(0.8); top: var(--inputTopMargin); @@ -316,17 +310,11 @@ form.semanticForms .floatLabelForm div label { color: var(--placeholderColor); touch-action: manipulation; } -form.semanticForms .floatLabelForm input::placeholder, -form.semanticForms .floatLabelForm textarea::placeholder { +form.semanticForms .floatLabelForm input::placeholder, form.semanticForms .floatLabelForm textarea::placeholder { color: var(--placeholderColor); opacity: 1; } -form.semanticForms .floatLabelForm div.col-1 dd, -form.semanticForms .floatLabelForm div.col-2 dd, -form.semanticForms .floatLabelForm div.col-3 dd, -form.semanticForms .floatLabelForm div.col-4 dd, -form.semanticForms .floatLabelForm div.col-5 dd, -form.semanticForms .floatLabelForm div.col-full dd { +form.semanticForms .floatLabelForm div.col-1 dd, form.semanticForms .floatLabelForm div.col-2 dd, form.semanticForms .floatLabelForm div.col-3 dd, form.semanticForms .floatLabelForm div.col-4 dd, form.semanticForms .floatLabelForm div.col-5 dd, form.semanticForms .floatLabelForm div.col-full dd { max-width: 100% !important; } form.semanticForms .floatLabelForm div.col-1 { @@ -345,7 +333,7 @@ form.semanticForms .floatLabelForm div.col-5 { grid-column: span 5; } form.semanticForms .floatLabelForm div.col-full { - grid-column: 1 / -1; + grid-column: 1/-1; } form.semanticForms input:-webkit-autofill, form.semanticForms input:-webkit-autofill:hover, @@ -375,23 +363,17 @@ form.semanticForms select:-webkit-autofill:active { } } @container (width < 1050px) { - form.semanticForms .col-4, - form.semanticForms .col-5 { + form.semanticForms .col-4, form.semanticForms .col-5 { grid-column: span 3 !important; } } @container (width < 800px) { - form.semanticForms .col-3, - form.semanticForms .col-4, - form.semanticForms .col-5 { + form.semanticForms .col-3, form.semanticForms .col-4, form.semanticForms .col-5 { grid-column: span 2 !important; } } @container (width < 550px) { - form.semanticForms .col-2, - form.semanticForms .col-3, - form.semanticForms .col-4, - form.semanticForms .col-5 { + form.semanticForms .col-2, form.semanticForms .col-3, form.semanticForms .col-4, form.semanticForms .col-5 { grid-column: span 1 !important; } } @@ -403,10 +385,10 @@ form.semanticForms.lowFlow fieldset dl { form.semanticForms.lowFlow fieldset dd { margin-bottom: 10px; } -form.semanticForms.lowFlow fieldset dd:not(.checkboxes) input[type="checkbox"] { +form.semanticForms.lowFlow fieldset dd:not(.checkboxes) input[type=checkbox] { margin-left: 10px; } -form.semanticForms.lowFlow fieldset dd input:not([type='submit']):not([type='reset']):not([type='image']):not([type=checkbox]):not([type=radio]):not([type="range"]), +form.semanticForms.lowFlow fieldset dd input:not([type=submit]):not([type=reset]):not([type=image]):not([type=checkbox]):not([type=radio]):not([type=range]), form.semanticForms.lowFlow fieldset dd select, form.semanticForms.lowFlow fieldset dd textarea { padding-right: 6px; @@ -415,3 +397,5 @@ form.semanticForms.lowFlow .checkboxes ul, form.semanticForms.lowFlow .radios ul { margin-top: calc(var(--inputTopMargin) / 2); } + +/*# sourceMappingURL=semanticForms.css.map */ diff --git a/semanticForms.css.map b/semanticForms.css.map new file mode 100644 index 0000000..818d5b2 --- /dev/null +++ b/semanticForms.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["semanticForms.scss"],"names":[],"mappings":"AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIF;EACE;;AAGA;EACE;EACA;EACA;EACA;EACA;;AAIF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EAEA;EACA;EACA;;AAEA;EACE;;AAEA;EACE;EACA;EAEA;;AAGA;EACE;;AAIJ;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAEA;EAEE;;AAQZ;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAKF;AAAA;AAAA;EAGE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EACE;;AAGF;AAAA;AAAA;EACE;EACA;;AAEA;AAAA;AAAA;EACE;;AAUJ;AAAA;AAAA;EACE;EACA;;AAGF;AAAA;AAAA;AAAA;AAAA;EAEE;EACA;;AAIJ;AAAA;EAEE;;AAIF;EACE;EACA;EACA;;AAGF;AAAA;EAGE;EACA;EACA;;AAEA;AAAA;EACE;;AAKJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAKF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;;AAKJ;EACE;EACA;;AAIF;AAAA;AAAA;EAGE;;AAIF;AAAA;AAAA;AAAA;EAIE;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;;AAOF;EACE;EACA;;AAGE;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;AAAA;AAAA;EAGE;;AAMA;AAAA;EACE;EACA;;AAGF;AAAA;EACE;EACA;;AAGF;AAAA;EACE;EACA;;AAGF;AAAA;EACE;EACA;;AAKA;AAAA;EACE;;AAGF;AAAA;EACE;;AAGF;AAAA;EACE;;AAGF;AAAA;EACE;;AAOR;EACE;;AAEA;EACE;EACA;EACA;;AAIJ;EACE;EACA;EACA;;AAKF;EACE;EACA;;AAaA;EACE;;AAIJ;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;AAEF;EACE;;AAON;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAYE;EACA;EACA;EACA;;AAIF;EACE;IACE;;;AAMJ;EACE;IACE;;;AAIJ;EACE;IACE;;;AAIJ;EACE;IACE;;;AAIJ;EACE;IACE;;;AASA;EACE;EACA;EACA;;AAGF;EACE;;AAIE;EACE;;AAKJ;AAAA;AAAA;EAGE;;AAMN;AAAA;EAEE","file":"semanticForms.css"} \ No newline at end of file diff --git a/semanticForms.less b/semanticForms.scss similarity index 100% rename from semanticForms.less rename to semanticForms.scss From dc77559559f076a7bc181482d357b7dd4dcae900 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Mon, 9 Sep 2024 14:05:34 -0400 Subject: [PATCH 20/60] updated package.json and README --- README.md | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b158d2a..90ededf 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,7 @@ See `semanticForms.html` or the [live demo](https://kethinov.github.io/semanticf - Fork/clone this repo. - `npm ci` -- Make your changes. If you want to alter the CSS, do the changes in the `.less` files. -- `npm run build`. The build step compiles the LESS file into CSS. +- Make your changes. If you want to alter the CSS, do the changes in the `.scss` files. +- `npm run build`. The build step compiles the SCSS file into CSS. - Test your changes by opening `semanticForms.html` in your browser. - Commit, push, open pull request. diff --git a/package.json b/package.json index 91e5072..523d2af 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "files": [ "semanticForms.css", "semanticForms.js", - "semanticForms.less" + "semanticForms.scss" ], "homepage": "https://github.com/kethinov/semanticforms", "license": "CC-BY-4.0", From 75a948058656e2fb28269f061ec5527209a33e9c Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Mon, 9 Sep 2024 14:20:38 -0400 Subject: [PATCH 21/60] clear button updates --- semanticForms.css | 9 ++++++--- semanticForms.css.map | 2 +- semanticForms.html | 7 +++++-- semanticForms.scss | 8 +++++--- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index 312eec3..b85a9a3 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -127,6 +127,11 @@ form.semanticForms select[disabled] + label, form.semanticForms textarea[disabled] + label { filter: brightness(50%); } +form.semanticForms input:not([type=submit]):not([type=reset]):not([type=image]):not([type=checkbox]):not([type=radio])[disabled] + label + button, +form.semanticForms select[disabled] + label + button, +form.semanticForms textarea[disabled] + label + button { + display: none; +} form.semanticForms input:not([type=submit]):not([type=reset]):not([type=image]):focus, form.semanticForms select:focus, form.semanticForms textarea:focus { @@ -182,8 +187,7 @@ form.semanticForms button.clear { -webkit-appearance: none; position: absolute; height: min-content; - top: var(--inputTopMargin); - bottom: 0; + top: calc(var(--inputTopMargin) + 6px); right: 0; width: 25px; height: 25px; @@ -200,7 +204,6 @@ form.semanticForms button.clear:hover, form.semanticForms button.clear:focus { filter: brightness(0.8); } form.semanticForms textarea + label + .clear { - margin: 6px; bottom: auto; } form.semanticForms input:placeholder-shown + label + .clear, diff --git a/semanticForms.css.map b/semanticForms.css.map index 818d5b2..1cea9e0 100644 --- a/semanticForms.css.map +++ b/semanticForms.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["semanticForms.scss"],"names":[],"mappings":"AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIF;EACE;;AAGA;EACE;EACA;EACA;EACA;EACA;;AAIF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EAEA;EACA;EACA;;AAEA;EACE;;AAEA;EACE;EACA;EAEA;;AAGA;EACE;;AAIJ;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAEA;EAEE;;AAQZ;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAKF;AAAA;AAAA;EAGE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EACE;;AAGF;AAAA;AAAA;EACE;EACA;;AAEA;AAAA;AAAA;EACE;;AAUJ;AAAA;AAAA;EACE;EACA;;AAGF;AAAA;AAAA;AAAA;AAAA;EAEE;EACA;;AAIJ;AAAA;EAEE;;AAIF;EACE;EACA;EACA;;AAGF;AAAA;EAGE;EACA;EACA;;AAEA;AAAA;EACE;;AAKJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAKF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;;AAKJ;EACE;EACA;;AAIF;AAAA;AAAA;EAGE;;AAIF;AAAA;AAAA;AAAA;EAIE;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;;AAOF;EACE;EACA;;AAGE;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;AAAA;AAAA;EAGE;;AAMA;AAAA;EACE;EACA;;AAGF;AAAA;EACE;EACA;;AAGF;AAAA;EACE;EACA;;AAGF;AAAA;EACE;EACA;;AAKA;AAAA;EACE;;AAGF;AAAA;EACE;;AAGF;AAAA;EACE;;AAGF;AAAA;EACE;;AAOR;EACE;;AAEA;EACE;EACA;EACA;;AAIJ;EACE;EACA;EACA;;AAKF;EACE;EACA;;AAaA;EACE;;AAIJ;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;AAEF;EACE;;AAON;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAYE;EACA;EACA;EACA;;AAIF;EACE;IACE;;;AAMJ;EACE;IACE;;;AAIJ;EACE;IACE;;;AAIJ;EACE;IACE;;;AAIJ;EACE;IACE;;;AASA;EACE;EACA;EACA;;AAGF;EACE;;AAIE;EACE;;AAKJ;AAAA;AAAA;EAGE;;AAMN;AAAA;EAEE","file":"semanticForms.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["semanticForms.scss"],"names":[],"mappings":"AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIF;EACE;;AAGA;EACE;EACA;EACA;EACA;EACA;;AAIF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EAEA;EACA;EACA;;AAEA;EACE;;AAEA;EACE;EACA;EAEA;;AAGA;EACE;;AAIJ;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAEA;EAEE;;AAQZ;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAKF;AAAA;AAAA;EAGE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EACE;;AAGF;AAAA;AAAA;EACE;EACA;;AAEA;AAAA;AAAA;EACE;;AAGF;AAAA;AAAA;EACE;;AAUJ;AAAA;AAAA;EACE;EACA;;AAGF;AAAA;AAAA;AAAA;AAAA;EAEE;EACA;;AAIJ;AAAA;EAEE;;AAIF;EACE;EACA;EACA;;AAGF;AAAA;EAGE;EACA;EACA;;AAEA;AAAA;EACE;;AAKJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAKF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;;AAKJ;EACE;;AAIF;AAAA;AAAA;EAGE;;AAIF;AAAA;AAAA;AAAA;EAIE;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;;AAOF;EACE;EACA;;AAGE;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;AAAA;AAAA;EAGE;;AAMA;AAAA;EACE;EACA;;AAGF;AAAA;EACE;EACA;;AAGF;AAAA;EACE;EACA;;AAGF;AAAA;EACE;EACA;;AAKA;AAAA;EACE;;AAGF;AAAA;EACE;;AAGF;AAAA;EACE;;AAGF;AAAA;EACE;;AAOR;EACE;;AAEA;EACE;EACA;EACA;;AAIJ;EACE;EACA;EACA;;AAKF;EACE;EACA;;AAaA;EACE;;AAIJ;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;AAEF;EACE;;AAON;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAYE;EACA;EACA;EACA;;AAIF;EACE;IACE;;;AAMJ;EACE;IACE;;;AAIJ;EACE;IACE;;;AAIJ;EACE;IACE;;;AAIJ;EACE;IACE;;;AASA;EACE;EACA;EACA;;AAGF;EACE;;AAIE;EACE;;AAKJ;AAAA;AAAA;EAGE;;AAMN;AAAA;EAEE","file":"semanticForms.css"} \ No newline at end of file diff --git a/semanticForms.html b/semanticForms.html index 8cb7f51..605d701 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -28,7 +28,7 @@

    Semantic Forms

    A pattern library of forms based on semantic HTML enhanced with a modern UX.

    - +
    Fieldset legend (high flow, JS enabled)
    @@ -62,6 +62,9 @@

    Semantic Forms

    +
    +
    +
    +

    Here is some subtext.

    diff --git a/semanticForms.scss b/semanticForms.scss index 0ea0555..afa74af 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -144,6 +144,10 @@ form.semanticForms { + label { filter: brightness(50%); } + + + label + button { + display: none; + } } } @@ -215,8 +219,7 @@ form.semanticForms { -webkit-appearance: none; position: absolute; height: min-content; - top: var(--inputTopMargin); // account for margin above each input - bottom: 0; + top: calc(var(--inputTopMargin) + 6px); // account for margin above each input right: 0; width: 25px; height: 25px; @@ -237,7 +240,6 @@ form.semanticForms { // custom styling of clear button on textarea textarea + label + .clear { - margin: 6px; bottom: auto; } From eae6668a7ab02df13c6222e25161ffdeb17e289a Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Mon, 9 Sep 2024 15:10:26 -0400 Subject: [PATCH 22/60] add darkening nested fieldsets, update CHANGELOG --- CHANGELOG.md | 10 +++++++--- semanticForms.css | 38 +++++++++++++++++++++----------------- semanticForms.css.map | 2 +- semanticForms.html | 20 ++++++++++++++++++-- semanticForms.scss | 26 ++++++++++++++++---------- 5 files changed, 63 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a930ed2..ae920d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,15 @@ ## Next version -- Rewrite of CSS, includes the following changes: +- Rewrite of CSS, includes the following changes and fixed: - Fieldset elements now utilize CSS grid to dynamically fill available space before wrapping to the next row. - - Input clear button is now a button element, allowing interaction via tab. - - Input clear button avoids overlap with scrollbars on textarea elements. + - Input clear button is now a `
    -
    +
    + + +
    @@ -405,6 +414,12 @@

    Low flow styling

    +
    +
    + + +
    +
    @@ -415,15 +430,18 @@

    Low flow styling

    -
    +
    + + +
    @@ -474,7 +492,10 @@

    Low flow styling

    -
    +
    + + +
    diff --git a/semanticForms.js b/semanticForms.js index 3590407..e31b791 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -64,8 +64,10 @@ window.semanticForms = () => { const newLabel = document.createElement('label') newLabel.setAttribute('for', input.id) newLabel.className = 'floatLabelFormAnimatedLabel' + newLabel.innerHTML = label.innerHTML label.setAttribute('hidden', 'hidden') + insertAfter(newLabel, input) } // #endregion diff --git a/semanticForms.scss b/semanticForms.scss index ffa9dc5..7524cda 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -156,7 +156,7 @@ form.semanticForms { outline: none; &:required { - + label::after { + + label:first-of-type:after { content: '*'; color: red; } @@ -170,7 +170,7 @@ form.semanticForms { cursor: not-allowed; opacity: 0.5; - + label { + + label:first-of-type { opacity: 0.5; } @@ -190,11 +190,11 @@ form.semanticForms { box-shadow: 0 0 0 1px var(--borderColor); } - &:focus:not([type=checkbox], [type=radio]) + label, - &:not(:placeholder-shown, [type=checkbox], [type=radio]) + label { - color: var(--formTextColor) !important; - transform: translateY(-150%) scale(0.7); - } + // &:focus:not([type=checkbox], [type=radio]) + label:first-of-type, + // &:not(:placeholder-shown, [type=checkbox], [type=radio]) + label:first-of-type { + // color: var(--formTextColor) !important; + // transform: translateY(-150%) scale(0.7); + // } } input:not([type='submit'], [type='reset'], [type='image'], [type=checkbox], [type=radio]), @@ -216,7 +216,7 @@ form.semanticForms { height: 1.3em; cursor: pointer; - & + label { + & + label:first-of-type { color: var(--formTextColor) !important; } } @@ -237,10 +237,10 @@ form.semanticForms { -moz-appearance: none; appearance: none; - // force label to be correct color - & + label { - color: var(--formTextColor) !important; - } + // // force label to be correct color + // & + label:first-of-type { + // color: var(--formTextColor) !important; + // } } textarea { @@ -325,7 +325,22 @@ form.semanticForms { width: 100%; dd:not(.singleCheckbox, .checkboxes, .radios) { - label { + input:not([type='submit'], [type='reset'], [type='image']), + select, + textarea { + &:focus:not([type=checkbox], [type=radio]) + label:first-of-type, + &:not(:placeholder-shown, [type=checkbox], [type=radio]) + label:first-of-type { + color: var(--formTextColor) !important; + transform: translateY(-150%) scale(0.7); + } + } + + select + label:first-of-type { + // force label to be correct color + color: var(--formTextColor) !important; + } + + label:first-of-type { line-height: 1.2; font-size: var(--inputFontSize); position: absolute; @@ -341,6 +356,14 @@ form.semanticForms { text-overflow: ellipsis; } + // subtext + label:nth-of-type(2) { + margin-top: -5px; + padding-left: 20px; + font-size: small; + color: var(--placeholderColor); + } + input, textarea, select { @@ -403,7 +426,7 @@ form.semanticForms { } } - label { + label:first-of-type { user-select: none; color: var(--placeholderColor); touch-action: manipulation; @@ -585,7 +608,6 @@ form.semanticForms { // #endregion - // #region invalid/valid styling input:not([type='submit'], [type='reset'], [type='image']), select, @@ -594,7 +616,7 @@ form.semanticForms { &:user-invalid { border: var(--invalidBorder) !important; - + label { + ~ label:nth-of-type(2) { color: var(--invalid) !important; } } @@ -603,7 +625,7 @@ form.semanticForms { &:required:user-valid { border: var(--validBorder) !important; - + label { + ~ label:nth-of-type(2) { color: var(--valid) !important; } } @@ -706,6 +728,12 @@ form.semanticForms { padding-right: 6px; } + // subtext + label { + margin-top: -5px; + font-size: small; + color: var(--placeholderColor); + } } } From 069009d8ec5d20e6ade4985098e5713eab334815 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Thu, 12 Sep 2024 14:17:51 -0400 Subject: [PATCH 44/60] update sample help text to show wrapping --- semanticForms.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/semanticForms.html b/semanticForms.html index 873b178..8de4624 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -147,7 +147,7 @@

    Default styling

    - +
    @@ -494,7 +494,7 @@

    Low flow styling

    - +
    From 9937746b15caaa460f51f4b068c1d62bd7f74083 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Thu, 12 Sep 2024 15:39:21 -0400 Subject: [PATCH 45/60] update README --- README.md | 108 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 81b244f..322b7d5 100644 --- a/README.md +++ b/README.md @@ -52,76 +52,90 @@ The float label input pattern is notoriously difficult to implement in a fashion ``` -### Specify fieldset columns -You can limit the number of columns on your forms using the `colspan-#` class on the `
    ` or `
    ` element. Applying the class to the `
    ` will apply it to all nested `
    ` elements. +### Add help text + +Include a label in the `
    ` element with a matching `for` attribute to place help text beneath the input. ```html
    - -
    -
    -
    -
    +
    +
    +
    + + +
    +
    + +``` -
    -
    +## Responsive columns +You can limit the number of columns on your forms using the `colspan-#` class on a `
    ` element. Applying the class to a `
    ` will apply that styling to all nested `
    ` elements. - -
    -
    -
    -
    +```html +
    +
    +
    +
    + +
    +
    + + +
    +
    +
    ``` ```html
    -
    - -
    -
    -
    +
    + +
    +
    +
    -
    -
    +
    +
    -
    -
    +
    +
    - +
    -
    -
    +
    +
    -
    -
    +
    +
    -
    -
    +
    +
    ``` ### Specify input columns -You can specify the number of columns an input will span using the `colspan-#` class on the `
    ` element. The inputs are responsive and will shrink according to available space. +You can specify the number of columns an input will span using the `colspan-#` class on the `
    ` element. The inputs are responsive and will shrink according to available space. Available numbered classes are `colspan-1` through `colspan-5`. + ```html
    +
    -
    -
    +
    +
    -
    -
    +
    +
    -
    -
    +
    @@ -133,17 +147,17 @@ You can specify the number of columns an input will span using the `colspan-#` c
    - -
    -
    +
    + +
    - -
    -
    +
    + +
    - -
    -
    + +
    +
    @@ -235,7 +249,9 @@ Not too different than other inputs: - Custom-styled select boxes with a custom drawn arrow graphic driven by SVG embedded in the CSS. - Custom-styled submit buttons to match the aesthetic of the custom-styled forms. +- Required inputs add a red asterisk to their labels. - Responsive: on wide screens, the forms split into multiple columns. On smaller screens, they collapse to a single column. +- Validation: Valid and invalid styling are automatically applied to all inputs, including select and textarea elements. Validation styling may be added manually using the `valid` and `invalid` classes for the input. `valid` styling is only applied to inputs that also have the `required` attribute. - Dark mode: apply an additional class of `dark` to your `
    ` elements to use the dark mode. - Low-flow mode that displays on old browsers, JS-disabled browsers, or can be activated manually by adding the `lowFlow` class to your `` element. The low-flow mode reverts the float label pattern to traditional labels and collapses the forms to single column mode, but preserves the other visual design enhancements driven purely by CSS. From 01b9eefa9d1ce4ab27aa5b3beec0375e1590580d Mon Sep 17 00:00:00 2001 From: Eric Newport Date: Fri, 13 Sep 2024 09:59:59 -0400 Subject: [PATCH 46/60] changelog --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 411a695..36cad94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,10 @@ - Breaking: Overhauled entire codebase to drive it using CSS grid instead of flexbox. This makes everything more flexible overall and fit more designs better. However the CSS and markup changes will likely cause breaking changes to previous integrations, so when upgrading make some time to visually test all your pages to alter any CSS overrides you had in place accordingly. You also might want to make some markup changes to make use of new available classes to tweak the fit of individual form fields on specific forms. - Altered fields to fit available space better at various screen sizes. - Added multiple utility classes that define how wide inputs will span in the responsive layout. -- Added form validation styles. -- Added asterisk that appears next to required inputs. +- Added support for input type=image. +- Added support for secondary labels. +- Added styling for invalid form fields. +- Added asterisk that appears on required inputs. - Improved accessibility considerably. Now has 100% Lighthouse score. - Added feature to progressively nest fieldsets with progressively darker/lighter background colors. - Fixed bug causing clear button appearing on disabled inputs. From 9edf205463f3f8e51e4c08204b6b30965c23038f Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Fri, 13 Sep 2024 10:43:24 -0400 Subject: [PATCH 47/60] various tweaks --- README.md | 3 + semanticForms.css | 78 ++++++++++++-------------- semanticForms.html | 53 ++++++++++++++++-- semanticForms.scss | 135 +++++++++++++++++++++------------------------ 4 files changed, 152 insertions(+), 117 deletions(-) diff --git a/README.md b/README.md index 322b7d5..d424153 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,9 @@ You can specify the number of columns an input will span using the `colspan-#` c ``` +> #### Low flow `colspan-#` +> To apply `colspan-#` styles to lowFlow form inputs, you will need to manually wrap your `
    ` and `
    ` elements in a `
    `. + ## Button groups You can align buttons side-by-side, or in left/right/center groups. diff --git a/semanticForms.css b/semanticForms.css index 302de1c..5d1929e 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -5,21 +5,20 @@ form.semanticForms { --buttonBackgroundColor: #f5f5f5; --borderColor: #c0c0c0; --subBorderColor: #c0c0c0; - --placeholderColor: #757575; + --placeholderColor: rgba(0, 0, 0, 0.75); --scrollbarColor: #c0c0c0; --clearButtonColor: #000; --buttonGradientLight: #fff; --buttonGradientDark: #c0c0c0; - --invalid: #ea868f; - --valid: #75b798; + --invalid: #f00; --invalidBorder: 2px solid var(--invalid); - --validBorder: 2px solid var(--valid); --inputHeight: 38px; --inputFontSize: 16px; --inputTopMargin: 15px; --inputMinWidth: 250px; --borderRadius: 10px; - --nestedFieldset: rgba(0,0,0,.05); + --nestedFieldset: rgba(0, 0, 0, .05); + --nestedInput: #fff; --border: 1px var(--borderColor) solid; --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); --customResizer: url("data:image/svg+xml;utf8,%3Csvg width='20' height='20' viewBox='0 0 5.2916665 5.2916666' version='1.1' id='svg5' xmlns='http://www.w3.org/2000/svg' xmlns:svg='http://www.w3.org/2000/svg'%3E%3Cdefs id='defs2' /%3E%3Cg id='layer1'%3E%3Cpath style='fill:%23aaa;stroke:%23aaa;stroke-width:0.264583;stroke-dasharray:none;stroke-opacity:1' d='M 2.8245112,5.0994569 C 4.9396993,2.9842685 4.9396993,2.9842685 4.9396993,2.9842685' id='path1034' /%3E%3Cpath style='fill:%23aaa;stroke:%23aaa;stroke-width:0.264583;stroke-dasharray:none;stroke-opacity:1' d='M 1.515747,5.0406977 C 4.8873304,1.6691138 4.8873304,1.6691138 4.8873304,1.6691138' id='path1034-1' /%3E%3Cpath style='fill:%23aaa;stroke:%23aaa;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1' d='M 0.20657789,5.0909782 C 4.9312207,0.3663348 4.9312207,0.3663348 4.9312207,0.3663348' id='path1034-9' /%3E%3C/g%3E%3C/svg%3E") ; @@ -33,12 +32,13 @@ form.semanticForms.dark { --buttonBackgroundColor: #454545; --borderColor: #656565; --subBorderColor: #3f3f3f; - --placeholderColor: #C9C9C9; + --placeholderColor: rgba(255, 255, 255, 0.85); --scrollbarColor: #373737; --clearButtonColor: #fff; --buttonGradientLight: #6f6f6f; --buttonGradientDark: #373737; - --nestedFieldset: rgba(255,255,255,.05); + --nestedFieldset: rgba(255, 255, 255, .05); + --nestedInput: rgba(255, 255, 255, .15); --border: none; --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); --customResizer: url("data:image/svg+xml;utf8,%3Csvg width='20' height='20' viewBox='0 0 5.2916665 5.2916666' version='1.1' id='svg5' xmlns='http://www.w3.org/2000/svg' xmlns:svg='http://www.w3.org/2000/svg'%3E%3Cdefs id='defs2' /%3E%3Cg id='layer1'%3E%3Cpath style='fill:%23c9c9c9;stroke:%23c9c9c9;stroke-width:0.264583;stroke-dasharray:none;stroke-opacity:1' d='M 2.8245112,5.0994569 C 4.9396993,2.9842685 4.9396993,2.9842685 4.9396993,2.9842685' id='path1034' /%3E%3Cpath style='fill:%23c9c9c9;stroke:%23c9c9c9;stroke-width:0.264583;stroke-dasharray:none;stroke-opacity:1' d='M 1.515747,5.0406977 C 4.8873304,1.6691138 4.8873304,1.6691138 4.8873304,1.6691138' id='path1034-1' /%3E%3Cpath style='fill:%23c9c9c9;stroke:%23c9c9c9;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1' d='M 0.20657789,5.0909782 C 4.9312207,0.3663348 4.9312207,0.3663348 4.9312207,0.3663348' id='path1034-9' /%3E%3C/g%3E%3C/svg%3E"); @@ -72,9 +72,14 @@ form.semanticForms fieldset { padding: 20px 10px; margin-bottom: 15px; } -form.semanticForms fieldset fieldset { +form.semanticForms fieldset > fieldset { background-color: var(--nestedFieldset); } +form.semanticForms fieldset > fieldset input:not([type=submit], [type=reset], [type=image], [type=checkbox], [type=radio]), +form.semanticForms fieldset > fieldset select, +form.semanticForms fieldset > fieldset textarea { + background: var(--nestedInput); +} form.semanticForms dl { display: grid; grid-template-columns: repeat(2, minmax(var(--inputMinWidth), 1fr)); @@ -105,6 +110,7 @@ form.semanticForms dl dd.checkboxes ul li, form.semanticForms dl dd.radios ul li gap: 5px; } form.semanticForms dl dd.checkboxes ul li label, form.semanticForms dl dd.radios ul li label { + font-size: var(--inputFontSize); margin-top: 2px; } form.semanticForms menu, form.semanticForms ul { @@ -175,8 +181,8 @@ form.semanticForms input[type=color] { } form.semanticForms input[type=checkbox], form.semanticForms input[type=radio] { - width: 1.3em; - height: 1.3em; + width: 1.4em; + height: 1.4em; cursor: pointer; } form.semanticForms input[type=checkbox] + label:first-of-type, @@ -263,6 +269,9 @@ form.semanticForms input[type=image]:hover, form.semanticForms button:not(.clear):hover { filter: brightness(1.05); } +form.semanticForms .floatLabelForm:not(:has(div:nth-of-type(2))) dd:not(.checkboxes, .radios) { + max-width: 450px; +} form.semanticForms .floatLabelForm div { position: relative; width: 100%; @@ -296,7 +305,7 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .rad margin-top: -5px; padding-left: 20px; font-size: small; - color: var(--placeholderColor); + color: var(--formTextColor); } form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea, @@ -339,40 +348,45 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .rad form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea:focus:-ms-input-placeholder { opacity: 1; } +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) label:first-of-type { + user-select: none; + color: var(--placeholderColor); + touch-action: manipulation; +} form.semanticForms .floatLabelForm div dt { position: relative; } -form.semanticForms .floatLabelForm div dt label:is([data-for=checkboxes], [data-for=radios]) { +form.semanticForms .floatLabelForm div dt label { + user-select: auto; color: var(--formTextColor); position: absolute; transform: translateY(-100%) scale(0.8); top: var(--inputTopMargin); } -form.semanticForms .floatLabelForm div label:first-of-type { - user-select: none; - color: var(--placeholderColor); - touch-action: manipulation; +form.semanticForms .floatLabelForm div:has(dd input:required) dt label::after { + content: "*"; + color: red; } form.semanticForms .floatLabelForm input::placeholder, form.semanticForms .floatLabelForm textarea::placeholder { color: var(--placeholderColor); opacity: 1; } -form.semanticForms .floatLabelForm div.colspan-full { +form.semanticForms div.colspan-full { grid-column: 1/-1; } -form.semanticForms .floatLabelForm div.colspan-5 { +form.semanticForms div.colspan-5 { grid-column: span 5; } -form.semanticForms .floatLabelForm div.colspan-4 { +form.semanticForms div.colspan-4 { grid-column: span 4; } -form.semanticForms .floatLabelForm div.colspan-3 { +form.semanticForms div.colspan-3 { grid-column: span 3; } -form.semanticForms .floatLabelForm div.colspan-2 { +form.semanticForms div.colspan-2 { grid-column: span 2; } -form.semanticForms .floatLabelForm div.colspan-1 { +form.semanticForms div.colspan-1 { grid-column: span 1; } form.semanticForms fieldset.colspan-full dl, @@ -473,20 +487,6 @@ form.semanticForms textarea.invalid ~ label:nth-of-type(2), form.semanticForms textarea:user-invalid ~ label:nth-of-type(2) { color: var(--invalid) !important; } -form.semanticForms input:not([type=submit], [type=reset], [type=image]).valid, form.semanticForms input:not([type=submit], [type=reset], [type=image]):required:user-valid, -form.semanticForms select.valid, -form.semanticForms select:required:user-valid, -form.semanticForms textarea.valid, -form.semanticForms textarea:required:user-valid { - border: var(--validBorder) !important; -} -form.semanticForms input:not([type=submit], [type=reset], [type=image]).valid ~ label:nth-of-type(2), form.semanticForms input:not([type=submit], [type=reset], [type=image]):required:user-valid ~ label:nth-of-type(2), -form.semanticForms select.valid ~ label:nth-of-type(2), -form.semanticForms select:required:user-valid ~ label:nth-of-type(2), -form.semanticForms textarea.valid ~ label:nth-of-type(2), -form.semanticForms textarea:required:user-valid ~ label:nth-of-type(2) { - color: var(--valid) !important; -} form.semanticForms input:-webkit-autofill, form.semanticForms input:-webkit-autofill:hover, form.semanticForms input:-webkit-autofill:focus, @@ -532,12 +532,6 @@ form.semanticForms.lowFlow dl dt:has(+ dd input:required) label::after { content: "*"; color: red; } -form.semanticForms.lowFlow dl dt:has(+ dd input:required:user-valid) label, form.semanticForms.lowFlow dl dt:has(+ dd input.valid) label { - color: var(--valid) !important; -} -form.semanticForms.lowFlow dl dt:has(+ dd input.invalid) label, form.semanticForms.lowFlow dl dt:has(+ dd input:user-invalid) label { - color: var(--invalid) !important; -} form.semanticForms.lowFlow dl dd { margin-bottom: 10px; } diff --git a/semanticForms.html b/semanticForms.html index 8de4624..816bd8b 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -46,11 +46,16 @@

    Default styling

    +
    +
    +
    +
    +
    Fieldset legend (high flow, JS enabled)
    -
    +
    @@ -367,7 +372,7 @@

    Default styling

    Flexbox button layout pattern with two submit buttons:

  • -
  • +
  • Flexbox button layout pattern with three submit buttons:

    @@ -396,11 +401,16 @@

    Low flow styling

    +
    +
    +
    +
    +
    Fieldset legend (low flow, JS disabled)
    -
    +
    @@ -543,6 +553,41 @@

    Low flow styling

    Colspan classes +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    colspan-1 @@ -669,7 +714,7 @@

    Low flow styling

    Flexbox button layout pattern with two submit buttons:

  • -
  • +
  • Flexbox button layout pattern with three submit buttons:

    diff --git a/semanticForms.scss b/semanticForms.scss index 7524cda..2470914 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -6,21 +6,21 @@ form.semanticForms { --buttonBackgroundColor: #f5f5f5; --borderColor: #c0c0c0; --subBorderColor: #c0c0c0; - --placeholderColor: #757575; + --placeholderColor: rgba(0, 0, 0, 0.75); + // --placeholderColor: #757575; --scrollbarColor: #c0c0c0; --clearButtonColor: #000; --buttonGradientLight: #fff; --buttonGradientDark: #c0c0c0; - --invalid: #ea868f; - --valid: #75b798; + --invalid: #f00; --invalidBorder: 2px solid var(--invalid); - --validBorder: 2px solid var(--valid); --inputHeight: 38px; --inputFontSize: 16px; --inputTopMargin: 15px; --inputMinWidth: 250px; --borderRadius: 10px; - --nestedFieldset: rgba(0,0,0,.05); + --nestedFieldset: rgba(0, 0, 0, .05); + --nestedInput: #fff; --border: 1px var(--borderColor) solid; --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); --customResizer: url("data:image/svg+xml;utf8,%3Csvg width='20' height='20' viewBox='0 0 5.2916665 5.2916666' version='1.1' id='svg5' xmlns='http://www.w3.org/2000/svg' xmlns:svg='http://www.w3.org/2000/svg'%3E%3Cdefs id='defs2' /%3E%3Cg id='layer1'%3E%3Cpath style='fill:%23aaa;stroke:%23aaa;stroke-width:0.264583;stroke-dasharray:none;stroke-opacity:1' d='M 2.8245112,5.0994569 C 4.9396993,2.9842685 4.9396993,2.9842685 4.9396993,2.9842685' id='path1034' /%3E%3Cpath style='fill:%23aaa;stroke:%23aaa;stroke-width:0.264583;stroke-dasharray:none;stroke-opacity:1' d='M 1.515747,5.0406977 C 4.8873304,1.6691138 4.8873304,1.6691138 4.8873304,1.6691138' id='path1034-1' /%3E%3Cpath style='fill:%23aaa;stroke:%23aaa;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1' d='M 0.20657789,5.0909782 C 4.9312207,0.3663348 4.9312207,0.3663348 4.9312207,0.3663348' id='path1034-9' /%3E%3C/g%3E%3C/svg%3E") @@ -34,12 +34,14 @@ form.semanticForms.dark { --buttonBackgroundColor: #454545; --borderColor: #656565; --subBorderColor: #3f3f3f; - --placeholderColor: #C9C9C9; + --placeholderColor: rgba(255, 255, 255, 0.85); + // --placeholderColor: #C9C9C9; --scrollbarColor: #373737; --clearButtonColor: #fff; --buttonGradientLight: #6f6f6f; --buttonGradientDark: #373737; - --nestedFieldset: rgba(255,255,255,.05); + --nestedFieldset: rgba(255, 255, 255, .05); + --nestedInput: rgba(255, 255, 255, .15); --border: none; --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); --customResizer: url("data:image/svg+xml;utf8,%3Csvg width='20' height='20' viewBox='0 0 5.2916665 5.2916666' version='1.1' id='svg5' xmlns='http://www.w3.org/2000/svg' xmlns:svg='http://www.w3.org/2000/svg'%3E%3Cdefs id='defs2' /%3E%3Cg id='layer1'%3E%3Cpath style='fill:%23c9c9c9;stroke:%23c9c9c9;stroke-width:0.264583;stroke-dasharray:none;stroke-opacity:1' d='M 2.8245112,5.0994569 C 4.9396993,2.9842685 4.9396993,2.9842685 4.9396993,2.9842685' id='path1034' /%3E%3Cpath style='fill:%23c9c9c9;stroke:%23c9c9c9;stroke-width:0.264583;stroke-dasharray:none;stroke-opacity:1' d='M 1.515747,5.0406977 C 4.8873304,1.6691138 4.8873304,1.6691138 4.8873304,1.6691138' id='path1034-1' /%3E%3Cpath style='fill:%23c9c9c9;stroke:%23c9c9c9;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1' d='M 0.20657789,5.0909782 C 4.9312207,0.3663348 4.9312207,0.3663348 4.9312207,0.3663348' id='path1034-9' /%3E%3C/g%3E%3C/svg%3E"); @@ -79,8 +81,15 @@ form.semanticForms { margin-bottom: 15px; // nested fieldsets are darkened - fieldset { + > fieldset { background-color: var(--nestedFieldset); + + // add opacity to styled inputs to prevent blending with background + input:not([type='submit'], [type='reset'], [type='image'], [type=checkbox], [type=radio]), + select, + textarea { + background: var(--nestedInput); + } } } @@ -119,6 +128,7 @@ form.semanticForms { label { // shift text down to match center + font-size: var(--inputFontSize); margin-top: 2px; } } @@ -189,12 +199,6 @@ form.semanticForms { outline: none; box-shadow: 0 0 0 1px var(--borderColor); } - - // &:focus:not([type=checkbox], [type=radio]) + label:first-of-type, - // &:not(:placeholder-shown, [type=checkbox], [type=radio]) + label:first-of-type { - // color: var(--formTextColor) !important; - // transform: translateY(-150%) scale(0.7); - // } } input:not([type='submit'], [type='reset'], [type='image'], [type=checkbox], [type=radio]), @@ -212,8 +216,8 @@ form.semanticForms { input[type=checkbox], input[type=radio] { // 30% larger based on parent font size - width: 1.3em; - height: 1.3em; + width: 1.4em; + height: 1.4em; cursor: pointer; & + label:first-of-type { @@ -236,11 +240,6 @@ form.semanticForms { -webkit-appearance: none; -moz-appearance: none; appearance: none; - - // // force label to be correct color - // & + label:first-of-type { - // color: var(--formTextColor) !important; - // } } textarea { @@ -320,6 +319,12 @@ form.semanticForms { // #region labels .floatLabelForm { + &:not(:has(div:nth-of-type(2))) { + dd:not(.checkboxes, .radios) { + max-width: 450px; + } + } + div { position: relative; width: 100%; @@ -361,7 +366,7 @@ form.semanticForms { margin-top: -5px; padding-left: 20px; font-size: small; - color: var(--placeholderColor); + color: var(--formTextColor); } input, @@ -412,13 +417,20 @@ form.semanticForms { } } } + + label:first-of-type { + user-select: none; + color: var(--placeholderColor); + touch-action: manipulation; + } } // top level label for checkbox and radio groups dt { position: relative; - label:is([data-for="checkboxes"], [data-for="radios"]) { + label { + user-select: auto; color: var(--formTextColor); position: absolute; transform: translateY(-100%) scale(0.8); @@ -426,10 +438,13 @@ form.semanticForms { } } - label:first-of-type { - user-select: none; - color: var(--placeholderColor); - touch-action: manipulation; + &:has(dd input:required) { + dt { + label::after { + content: '*'; + color: red; + } + } } } @@ -441,31 +456,32 @@ form.semanticForms { } // #endregion - // #region colspan classes - div { - &.colspan-full { - grid-column: 1 / -1; - } + } - &.colspan-5 { - grid-column: span 5; - } + // #region colspan classes + div { + &.colspan-full { + grid-column: 1 / -1; + } - &.colspan-4 { - grid-column: span 4; - } + &.colspan-5 { + grid-column: span 5; + } - &.colspan-3 { - grid-column: span 3; - } + &.colspan-4 { + grid-column: span 4; + } - &.colspan-2 { - grid-column: span 2; - } + &.colspan-3 { + grid-column: span 3; + } - &.colspan-1 { - grid-column: span 1; - } + &.colspan-2 { + grid-column: span 2; + } + + &.colspan-1 { + grid-column: span 1; } } @@ -608,7 +624,7 @@ form.semanticForms { // #endregion - // #region invalid/valid styling + // #region invalid styling input:not([type='submit'], [type='reset'], [type='image']), select, textarea { @@ -620,15 +636,6 @@ form.semanticForms { color: var(--invalid) !important; } } - - &.valid, - &:required:user-valid { - border: var(--validBorder) !important; - - ~ label:nth-of-type(2) { - color: var(--valid) !important; - } - } } // #endregion @@ -694,20 +701,6 @@ form.semanticForms { color: red; } } - - &:has(+ dd input:required:user-valid), - &:has(+ dd input.valid) { - label { - color: var(--valid) !important; - } - } - - &:has(+ dd input.invalid), - &:has(+ dd input:user-invalid) { - label { - color: var(--invalid) !important; - } - } } From 88413aef99c1631d3b0a9b2858b64681e20fea3e Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Fri, 13 Sep 2024 10:55:44 -0400 Subject: [PATCH 48/60] update html validation --- semanticForms.css | 2 +- semanticForms.html | 36 ++++++++++++++++++------------------ semanticForms.scss | 4 +--- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index 5d1929e..9af1fb5 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -270,7 +270,7 @@ form.semanticForms button:not(.clear):hover { filter: brightness(1.05); } form.semanticForms .floatLabelForm:not(:has(div:nth-of-type(2))) dd:not(.checkboxes, .radios) { - max-width: 450px; + max-width: 350px; } form.semanticForms .floatLabelForm div { position: relative; diff --git a/semanticForms.html b/semanticForms.html index 816bd8b..769f4e9 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -402,8 +402,8 @@

    Low flow styling

    -
    -
    +
    +
    @@ -555,36 +555,36 @@

    Low flow styling

    -
    -
    +
    +
    -
    -
    +
    +
    -
    -
    +
    +
    -
    -
    +
    +
    -
    -
    +
    +
    -
    -
    +
    +
    -
    -
    +
    +
    -
    -
    +
    +
    diff --git a/semanticForms.scss b/semanticForms.scss index 2470914..a55195f 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -7,7 +7,6 @@ form.semanticForms { --borderColor: #c0c0c0; --subBorderColor: #c0c0c0; --placeholderColor: rgba(0, 0, 0, 0.75); - // --placeholderColor: #757575; --scrollbarColor: #c0c0c0; --clearButtonColor: #000; --buttonGradientLight: #fff; @@ -35,7 +34,6 @@ form.semanticForms.dark { --borderColor: #656565; --subBorderColor: #3f3f3f; --placeholderColor: rgba(255, 255, 255, 0.85); - // --placeholderColor: #C9C9C9; --scrollbarColor: #373737; --clearButtonColor: #fff; --buttonGradientLight: #6f6f6f; @@ -321,7 +319,7 @@ form.semanticForms { .floatLabelForm { &:not(:has(div:nth-of-type(2))) { dd:not(.checkboxes, .radios) { - max-width: 450px; + max-width: 350px; } } From 09cd20c278e974a4ad4c6da69d891dadadccad9b Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Fri, 13 Sep 2024 12:27:04 -0400 Subject: [PATCH 49/60] add p tag support, fix clear button tabindex --- semanticForms.css | 13 +++++++++++++ semanticForms.html | 40 ++++++++++++++++++++++++++++++++++++++++ semanticForms.js | 1 + semanticForms.scss | 16 ++++++++++++++++ 4 files changed, 70 insertions(+) diff --git a/semanticForms.css b/semanticForms.css index 9af1fb5..72f18e4 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -113,6 +113,19 @@ form.semanticForms dl dd.checkboxes ul li label, form.semanticForms dl dd.radios font-size: var(--inputFontSize); margin-top: 2px; } +form.semanticForms p { + display: flex; + flex-direction: column; + gap: 5px; +} +form.semanticForms p input, form.semanticForms p select, form.semanticForms p textarea { + max-width: 350px; +} +form.semanticForms p:has(input[type=checkbox], input[type=radio]) { + display: flex; + flex-direction: row; + align-items: center; +} form.semanticForms menu, form.semanticForms ul { display: flex; justify-content: space-between; diff --git a/semanticForms.html b/semanticForms.html index 769f4e9..4bafd9e 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -382,6 +382,26 @@

    Default styling

  • + +
    + P tag elements + +

    + + +

    +

    + + +

    +

    + + +

    +

    + +

    +

    Low flow styling

    @@ -708,6 +728,26 @@

    Low flow styling

    +
    + P tag elements + +

    + + +

    +

    + + +

    +

    + + +

    +

    + +

    +
    + diff --git a/semanticForms.js b/semanticForms.js index e31b791..2a358da 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -87,6 +87,7 @@ window.semanticForms = () => { const clearBtn = document.createElement('button') clearBtn.type = 'button' clearBtn.ariaLabel = 'Clear input' + clearBtn.tabIndex = 1 clearBtn.innerHTML = '' clearBtn.classList.add('clear') clearBtn.addEventListener('click', () => { diff --git a/semanticForms.scss b/semanticForms.scss index a55195f..df82a73 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -134,6 +134,22 @@ form.semanticForms { } } + p { + display: flex; + flex-direction: column; + gap: 5px; + + input, select, textarea { + max-width: 350px; + } + + &:has(input[type='checkbox'], input[type='radio']) { + display: flex; + flex-direction: row; + align-items: center; + } + } + menu, ul { display: flex; justify-content: space-between; From 006f720043783ba707c1dc45bbcb298329460e5b Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Fri, 13 Sep 2024 12:35:50 -0400 Subject: [PATCH 50/60] update p tag rules --- semanticForms.css | 11 ++++++----- semanticForms.html | 6 ++++++ semanticForms.scss | 15 ++++++++++----- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index 72f18e4..6c4c18f 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -113,18 +113,19 @@ form.semanticForms dl dd.checkboxes ul li label, form.semanticForms dl dd.radios font-size: var(--inputFontSize); margin-top: 2px; } -form.semanticForms p { +form.semanticForms p input, form.semanticForms p select, form.semanticForms p textarea { + max-width: 350px; +} +form.semanticForms p:has(input:not([type=checkbox], [type=radio]), textarea):has(label) { display: flex; flex-direction: column; gap: 5px; } -form.semanticForms p input, form.semanticForms p select, form.semanticForms p textarea { - max-width: 350px; -} -form.semanticForms p:has(input[type=checkbox], input[type=radio]) { +form.semanticForms p:has(input[type=checkbox], input[type=radio]):has(label) { display: flex; flex-direction: row; align-items: center; + gap: 5px; } form.semanticForms menu, form.semanticForms ul { display: flex; diff --git a/semanticForms.html b/semanticForms.html index 4bafd9e..4c3cbdd 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -401,6 +401,9 @@

    Default styling

    +

    + Some regular text with other elements inside of it +

    @@ -746,6 +749,9 @@

    Low flow styling

    +

    + Some regular text with other elements inside of it +

    diff --git a/semanticForms.scss b/semanticForms.scss index df82a73..7611f2d 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -135,18 +135,23 @@ form.semanticForms { } p { - display: flex; - flex-direction: column; - gap: 5px; - input, select, textarea { max-width: 350px; } - &:has(input[type='checkbox'], input[type='radio']) { + // input/label combo + &:has(input:not([type='checkbox'], [type='radio']), textarea):has(label) { + display: flex; + flex-direction: column; + gap: 5px; + } + + // checkbox or radio/label combo + &:has(input[type='checkbox'], input[type='radio']):has(label) { display: flex; flex-direction: row; align-items: center; + gap: 5px; } } From 7e217ecef69054bb3d3ac401770e5bca87ad5562 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Fri, 13 Sep 2024 12:41:10 -0400 Subject: [PATCH 51/60] update p tag again --- semanticForms.css | 4 ++-- semanticForms.js | 2 +- semanticForms.scss | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index 6c4c18f..225f4c9 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -116,12 +116,12 @@ form.semanticForms dl dd.checkboxes ul li label, form.semanticForms dl dd.radios form.semanticForms p input, form.semanticForms p select, form.semanticForms p textarea { max-width: 350px; } -form.semanticForms p:has(input:not([type=checkbox], [type=radio]), textarea):has(label) { +form.semanticForms p:has(input:not([type=checkbox], [type=radio]), textarea, label) { display: flex; flex-direction: column; gap: 5px; } -form.semanticForms p:has(input[type=checkbox], input[type=radio]):has(label) { +form.semanticForms p:has(input[type=checkbox], input[type=radio], label) { display: flex; flex-direction: row; align-items: center; diff --git a/semanticForms.js b/semanticForms.js index 2a358da..e60e5c6 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -87,7 +87,7 @@ window.semanticForms = () => { const clearBtn = document.createElement('button') clearBtn.type = 'button' clearBtn.ariaLabel = 'Clear input' - clearBtn.tabIndex = 1 + clearBtn.tabIndex = 0 clearBtn.innerHTML = '' clearBtn.classList.add('clear') clearBtn.addEventListener('click', () => { diff --git a/semanticForms.scss b/semanticForms.scss index 7611f2d..f0f9fb7 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -140,14 +140,14 @@ form.semanticForms { } // input/label combo - &:has(input:not([type='checkbox'], [type='radio']), textarea):has(label) { + &:has(input:not([type='checkbox'], [type='radio']), textarea, label) { display: flex; flex-direction: column; gap: 5px; } // checkbox or radio/label combo - &:has(input[type='checkbox'], input[type='radio']):has(label) { + &:has(input[type='checkbox'], input[type='radio'], label) { display: flex; flex-direction: row; align-items: center; From 17516d063beb53ce8ab20bb4cecbcb3ea4631237 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Fri, 13 Sep 2024 13:09:33 -0400 Subject: [PATCH 52/60] set clear button to tabindex to -1 --- semanticForms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/semanticForms.js b/semanticForms.js index e60e5c6..11cb39f 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -87,7 +87,7 @@ window.semanticForms = () => { const clearBtn = document.createElement('button') clearBtn.type = 'button' clearBtn.ariaLabel = 'Clear input' - clearBtn.tabIndex = 0 + clearBtn.tabIndex = -1 clearBtn.innerHTML = '' clearBtn.classList.add('clear') clearBtn.addEventListener('click', () => { From e24aac0654dff39e05e9172f30589eb2e348292a Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Fri, 13 Sep 2024 13:46:24 -0400 Subject: [PATCH 53/60] upgrade required asterisk, add placeholder fade --- semanticForms.css | 27 ++++++++++++++------------- semanticForms.html | 4 ++-- semanticForms.js | 12 ++++++++++++ semanticForms.scss | 30 ++++++++++++++++-------------- 4 files changed, 44 insertions(+), 29 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index 225f4c9..8956c3d 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -151,12 +151,6 @@ form.semanticForms textarea { touch-action: manipulation; outline: none; } -form.semanticForms input:not([type=submit], [type=reset], [type=image], [type=checkbox], [type=radio]):required + label:first-of-type:after, -form.semanticForms select:required + label:first-of-type:after, -form.semanticForms textarea:required + label:first-of-type:after { - content: "*"; - color: red; -} form.semanticForms input:not([type=submit], [type=reset], [type=image], [type=checkbox], [type=radio]):not([type=range]), form.semanticForms select:not([type=range]), form.semanticForms textarea:not([type=range]) { @@ -329,22 +323,22 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .rad form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input::placeholder, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea::placeholder { opacity: 0; - transition: inherit; + transition: opacity 250ms; } form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input::-moz-placeholder, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea::-moz-placeholder { opacity: 0; - transition: inherit; + transition: opacity 250ms; } form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input::-webkit-input-placeholder, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea::-webkit-input-placeholder { opacity: 0; - transition: inherit; + transition: opacity 250ms; } form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input:-ms-input-placeholder, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea:-ms-input-placeholder { opacity: 0; - transition: inherit; + transition: opacity 250ms; } form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input:focus::placeholder, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea:focus::placeholder { @@ -367,6 +361,11 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .rad color: var(--placeholderColor); touch-action: manipulation; } +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) label:first-of-type span { + cursor: help; + pointer-events: auto; + color: red; +} form.semanticForms .floatLabelForm div dt { position: relative; } @@ -377,8 +376,10 @@ form.semanticForms .floatLabelForm div dt label { transform: translateY(-100%) scale(0.8); top: var(--inputTopMargin); } -form.semanticForms .floatLabelForm div:has(dd input:required) dt label::after { - content: "*"; +form.semanticForms .floatLabelForm div:has(dd input:required) dt label > span { + margin-left: 5px; + cursor: help; + pointer-events: auto; color: red; } form.semanticForms .floatLabelForm input::placeholder, form.semanticForms .floatLabelForm textarea::placeholder { @@ -543,7 +544,7 @@ form.semanticForms.lowFlow dl > dt:nth-of-type(2n + 2), form.semanticForms.lowFl grid-column: 2; } form.semanticForms.lowFlow dl dt:has(+ dd input:required) label::after { - content: "*"; + content: " *"; color: red; } form.semanticForms.lowFlow dl dd { diff --git a/semanticForms.html b/semanticForms.html index 4c3cbdd..fac8363 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -43,7 +43,7 @@

    Default styling

    -
    +
    @@ -104,7 +104,7 @@

    Default styling

      -
    • +
    diff --git a/semanticForms.js b/semanticForms.js index 11cb39f..7d868e3 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -51,6 +51,13 @@ window.semanticForms = () => { } newLabel.innerHTML = label.innerHTML + + if (dd.querySelector(':required')) { + if (!label.querySelector('span')) { + label.innerHTML += '*' + } + } + if (!dd.querySelector('label')) dd.append(newLabel) } @@ -66,6 +73,11 @@ window.semanticForms = () => { newLabel.className = 'floatLabelFormAnimatedLabel' newLabel.innerHTML = label.innerHTML + + if (input.hasAttribute('required')) { + newLabel.innerHTML += ' *' + } + label.setAttribute('hidden', 'hidden') insertAfter(newLabel, input) diff --git a/semanticForms.scss b/semanticForms.scss index f0f9fb7..61d1591 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -184,13 +184,6 @@ form.semanticForms { touch-action: manipulation; outline: none; - &:required { - + label:first-of-type:after { - content: '*'; - color: red; - } - } - &:not([type="range"]) { padding: 6px 30px 6px 20px; } @@ -399,22 +392,22 @@ form.semanticForms { // hide placeholder content until input is focused &::placeholder { opacity: 0; - transition: inherit; + transition: opacity 250ms; } &::-moz-placeholder { opacity: 0; - transition: inherit; + transition: opacity 250ms; } &::-webkit-input-placeholder { opacity: 0; - transition: inherit; + transition: opacity 250ms; } &:-ms-input-placeholder { opacity: 0; - transition: inherit; + transition: opacity 250ms; } // show placeholder content when focused @@ -441,6 +434,12 @@ form.semanticForms { user-select: none; color: var(--placeholderColor); touch-action: manipulation; + + span { + cursor: help; + pointer-events: auto; + color: red; + } } } @@ -459,10 +458,13 @@ form.semanticForms { &:has(dd input:required) { dt { - label::after { - content: '*'; + label > span { + margin-left: 5px; + cursor: help; + pointer-events: auto; color: red; } + } } } @@ -716,7 +718,7 @@ form.semanticForms { // add required asterisk &:has(+ dd input:required) { label::after { - content: '*'; + content: ' *'; color: red; } } From bc04a879db0a0ca84eea18126348c5bf951fe9a6 Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Fri, 13 Sep 2024 14:16:24 -0400 Subject: [PATCH 54/60] tweaks to textarea, update README --- README.md | 25 ++++++++++++++++++++++++- semanticForms.css | 4 +++- semanticForms.html | 27 ++++++++++++++++++++++++++- semanticForms.js | 12 ++++++------ semanticForms.scss | 4 +++- 5 files changed, 62 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index d424153..d3ae30b 100644 --- a/README.md +++ b/README.md @@ -248,13 +248,36 @@ Not too different than other inputs: ``` +## Validation styles + +Inputs with the `required` attribution will result in a visual indicator (*) being added to its label. You can disable this indicator with the `data-no-asterisk` attribute on the label element: + +```html +
    +
    +
    +
    +
    +
    +``` + +You can adjust the tooltip text of the asterisk with the `data-asterisk-text` attribute: + +```html +
    +
    +
    +
    +
    +
    +``` ## Other features - Custom-styled select boxes with a custom drawn arrow graphic driven by SVG embedded in the CSS. - Custom-styled submit buttons to match the aesthetic of the custom-styled forms. - Required inputs add a red asterisk to their labels. - Responsive: on wide screens, the forms split into multiple columns. On smaller screens, they collapse to a single column. -- Validation: Valid and invalid styling are automatically applied to all inputs, including select and textarea elements. Validation styling may be added manually using the `valid` and `invalid` classes for the input. `valid` styling is only applied to inputs that also have the `required` attribute. +- Validation: Invalid inputs are styled automatically after the user leaves the form input. Validation styling may be added manually using the `invalid` class. - Dark mode: apply an additional class of `dark` to your `
    ` elements to use the dark mode. - Low-flow mode that displays on old browsers, JS-disabled browsers, or can be activated manually by adding the `lowFlow` class to your `` element. The low-flow mode reverts the float label pattern to traditional labels and collapses the forms to single column mode, but preserves the other visual design enhancements driven purely by CSS. diff --git a/semanticForms.css b/semanticForms.css index 8956c3d..a30727b 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -277,7 +277,7 @@ form.semanticForms input[type=image]:hover, form.semanticForms button:not(.clear):hover { filter: brightness(1.05); } -form.semanticForms .floatLabelForm:not(:has(div:nth-of-type(2))) dd:not(.checkboxes, .radios) { +form.semanticForms .floatLabelForm:not(:has(div:nth-of-type(2))) dd:not(.checkboxes, .radios):not(:has(textarea)) { max-width: 350px; } form.semanticForms .floatLabelForm div { @@ -328,6 +328,7 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .rad form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input::-moz-placeholder, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea::-moz-placeholder { opacity: 0; + visibility: hidden; transition: opacity 250ms; } form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input::-webkit-input-placeholder, @@ -347,6 +348,7 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .rad form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input:focus::-moz-placeholder, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea:focus::-moz-placeholder { opacity: 1; + visibility: visible; } form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input:focus::-webkit-input-placeholder, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea:focus::-webkit-input-placeholder { diff --git a/semanticForms.html b/semanticForms.html index fac8363..66b898d 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -31,6 +31,16 @@

    Semantic Forms

    A pattern library of forms based on semantic HTML enhanced with a modern UX.

    Default styling

    + + +
    +
    +
    + + +
    +
    +
    @@ -81,6 +91,12 @@

    Default styling

    +
    +
    + +
    +
    +
    @@ -104,12 +120,21 @@

    Default styling

      -
    • +
    +
    +
    +
      +
    • +
    • +
    • +
    +
    +
    diff --git a/semanticForms.js b/semanticForms.js index 7d868e3..1c13109 100644 --- a/semanticForms.js +++ b/semanticForms.js @@ -52,10 +52,9 @@ window.semanticForms = () => { newLabel.innerHTML = label.innerHTML - if (dd.querySelector(':required')) { - if (!label.querySelector('span')) { - label.innerHTML += '*' - } + if (dd.querySelector(':required') && label.getAttribute('data-no-asterisk') === null && !label.querySelector('span')) { + const text = label.getAttribute('data-asterisk-text') || 'This field is required.' + label.innerHTML += `*` } if (!dd.querySelector('label')) dd.append(newLabel) @@ -74,8 +73,9 @@ window.semanticForms = () => { newLabel.innerHTML = label.innerHTML - if (input.hasAttribute('required')) { - newLabel.innerHTML += ' *' + if (input.hasAttribute('required') && label.getAttribute('data-no-asterisk') === null && !label.querySelector('span')) { + const text = label.getAttribute('data-asterisk-text') || 'This field is required.' + newLabel.innerHTML += ` *` } label.setAttribute('hidden', 'hidden') diff --git a/semanticForms.scss b/semanticForms.scss index 61d1591..c3ec89d 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -332,7 +332,7 @@ form.semanticForms { // #region labels .floatLabelForm { &:not(:has(div:nth-of-type(2))) { - dd:not(.checkboxes, .radios) { + dd:not(.checkboxes, .radios):not(:has(textarea)) { max-width: 350px; } } @@ -397,6 +397,7 @@ form.semanticForms { &::-moz-placeholder { opacity: 0; + visibility: hidden; transition: opacity 250ms; } @@ -418,6 +419,7 @@ form.semanticForms { &::-moz-placeholder { opacity: 1; + visibility: visible; } &::-webkit-input-placeholder { From 32f8c962ae0343a8e81361990e3b8ec67c8d10da Mon Sep 17 00:00:00 2001 From: Alex Widener Date: Fri, 13 Sep 2024 14:26:22 -0400 Subject: [PATCH 55/60] tweaks --- semanticForms.css | 6 ++++-- semanticForms.html | 9 --------- semanticForms.scss | 3 +-- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index a30727b..83b77cc 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -320,6 +320,10 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .rad form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) select { margin-top: var(--inputTopMargin); } +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input, +form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea { + transition: opacity 250ms; +} form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input::placeholder, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea::placeholder { opacity: 0; @@ -328,7 +332,6 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .rad form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input::-moz-placeholder, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea::-moz-placeholder { opacity: 0; - visibility: hidden; transition: opacity 250ms; } form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input::-webkit-input-placeholder, @@ -348,7 +351,6 @@ form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .rad form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input:focus::-moz-placeholder, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea:focus::-moz-placeholder { opacity: 1; - visibility: visible; } form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) input:focus::-webkit-input-placeholder, form.semanticForms .floatLabelForm div dd:not(.singleCheckbox, .checkboxes, .radios) textarea:focus::-webkit-input-placeholder { diff --git a/semanticForms.html b/semanticForms.html index 66b898d..04c29d2 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -32,15 +32,6 @@

    Semantic Forms

    Default styling

    - -
    -
    -
    - - -
    -
    -
    diff --git a/semanticForms.scss b/semanticForms.scss index c3ec89d..8325292 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -389,6 +389,7 @@ form.semanticForms { input, textarea { + transition: opacity 250ms; // hide placeholder content until input is focused &::placeholder { opacity: 0; @@ -397,7 +398,6 @@ form.semanticForms { &::-moz-placeholder { opacity: 0; - visibility: hidden; transition: opacity 250ms; } @@ -419,7 +419,6 @@ form.semanticForms { &::-moz-placeholder { opacity: 1; - visibility: visible; } &::-webkit-input-placeholder { From 30dec685475ceea0d4477db6093f427dd7e10a34 Mon Sep 17 00:00:00 2001 From: Eric Newport Date: Fri, 13 Sep 2024 14:27:13 -0400 Subject: [PATCH 56/60] small aesthetic adjustment --- semanticForms.css | 2 +- semanticForms.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index a30727b..96c082d 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -69,7 +69,7 @@ form.semanticForms fieldset { display: flex; flex-direction: column; gap: 5px; - padding: 20px 10px; + padding: 10px 10px 20px 10px; margin-bottom: 15px; } form.semanticForms fieldset > fieldset { diff --git a/semanticForms.scss b/semanticForms.scss index c3ec89d..849222e 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -75,7 +75,7 @@ form.semanticForms { display: flex; flex-direction: column; gap: 5px; - padding: 20px 10px; + padding: 10px 10px 20px 10px; margin-bottom: 15px; // nested fieldsets are darkened From 8f2c1cefb4f8186c4284412030f38cea73980242 Mon Sep 17 00:00:00 2001 From: Eric Newport Date: Sat, 14 Sep 2024 21:41:45 -0400 Subject: [PATCH 57/60] slight improvement for buttons on firefox --- semanticForms.css | 1 + semanticForms.scss | 1 + 2 files changed, 2 insertions(+) diff --git a/semanticForms.css b/semanticForms.css index 019cf68..c41c1ca 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -257,6 +257,7 @@ form.semanticForms button:not(.clear) { border-radius: 20px; padding: 5px 25px; font-size: 100%; + line-height: 1; } form.semanticForms input[type=submit]:active, form.semanticForms input[type=submit]:focus, form.semanticForms input[type=reset]:active, diff --git a/semanticForms.scss b/semanticForms.scss index 61bf5b7..8fad8c8 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -310,6 +310,7 @@ form.semanticForms { border-radius: 20px; padding: 5px 25px; font-size: 100%; + line-height: 1; &:active, &:focus { From a3fffb9b3fef12df52d5a2ddae1d86437d9affdc Mon Sep 17 00:00:00 2001 From: Eric Newport Date: Sat, 14 Sep 2024 21:43:27 -0400 Subject: [PATCH 58/60] consistent borders for invalid fields --- semanticForms.css | 2 +- semanticForms.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/semanticForms.css b/semanticForms.css index c41c1ca..54412c0 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -11,7 +11,7 @@ form.semanticForms { --buttonGradientLight: #fff; --buttonGradientDark: #c0c0c0; --invalid: #f00; - --invalidBorder: 2px solid var(--invalid); + --invalidBorder: 1px solid var(--invalid); --inputHeight: 38px; --inputFontSize: 16px; --inputTopMargin: 15px; diff --git a/semanticForms.scss b/semanticForms.scss index 8fad8c8..38b564d 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -12,7 +12,7 @@ form.semanticForms { --buttonGradientLight: #fff; --buttonGradientDark: #c0c0c0; --invalid: #f00; - --invalidBorder: 2px solid var(--invalid); + --invalidBorder: 1px solid var(--invalid); --inputHeight: 38px; --inputFontSize: 16px; --inputTopMargin: 15px; From d748b4d60ef0208936e125578462ceaca3d13268 Mon Sep 17 00:00:00 2001 From: Eric Newport Date: Sat, 14 Sep 2024 21:49:34 -0400 Subject: [PATCH 59/60] crisper borders on nested fieldsets --- semanticForms.css | 3 +++ semanticForms.scss | 3 +++ 2 files changed, 6 insertions(+) diff --git a/semanticForms.css b/semanticForms.css index 54412c0..f8932b3 100644 --- a/semanticForms.css +++ b/semanticForms.css @@ -18,6 +18,7 @@ form.semanticForms { --inputMinWidth: 250px; --borderRadius: 10px; --nestedFieldset: rgba(0, 0, 0, .05); + --nestedFieldsetBorder: 1px rgba(0, 0, 0, .2) solid; --nestedInput: #fff; --border: 1px var(--borderColor) solid; --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); @@ -38,6 +39,7 @@ form.semanticForms.dark { --buttonGradientLight: #6f6f6f; --buttonGradientDark: #373737; --nestedFieldset: rgba(255, 255, 255, .05); + --nestedFieldsetBorder: 1px rgba(255, 255, 255, .1) solid; --nestedInput: rgba(255, 255, 255, .15); --border: none; --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); @@ -74,6 +76,7 @@ form.semanticForms fieldset { } form.semanticForms fieldset > fieldset { background-color: var(--nestedFieldset); + border: var(--nestedFieldsetBorder); } form.semanticForms fieldset > fieldset input:not([type=submit], [type=reset], [type=image], [type=checkbox], [type=radio]), form.semanticForms fieldset > fieldset select, diff --git a/semanticForms.scss b/semanticForms.scss index 38b564d..3ff0348 100644 --- a/semanticForms.scss +++ b/semanticForms.scss @@ -19,6 +19,7 @@ form.semanticForms { --inputMinWidth: 250px; --borderRadius: 10px; --nestedFieldset: rgba(0, 0, 0, .05); + --nestedFieldsetBorder: 1px rgba(0, 0, 0, .2) solid; --nestedInput: #fff; --border: 1px var(--borderColor) solid; --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23000'%3E%3Cpolygon points='0,0 100,0 50,50'/%3E%3C/svg%3E"); @@ -39,6 +40,7 @@ form.semanticForms.dark { --buttonGradientLight: #6f6f6f; --buttonGradientDark: #373737; --nestedFieldset: rgba(255, 255, 255, .05); + --nestedFieldsetBorder: 1px rgba(255, 255, 255, .1) solid; --nestedInput: rgba(255, 255, 255, .15); --border: none; --selectIcon: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23fff'%3E%3Cpolygon stroke='%23fff' points='0,0 100,0 50,50'/%3E%3C/svg%3E"); @@ -81,6 +83,7 @@ form.semanticForms { // nested fieldsets are darkened > fieldset { background-color: var(--nestedFieldset); + border: var(--nestedFieldsetBorder); // add opacity to styled inputs to prevent blending with background input:not([type='submit'], [type='reset'], [type='image'], [type=checkbox], [type=radio]), From cb067b496cb1053c21b4d75dbe0a9e20c2f37051 Mon Sep 17 00:00:00 2001 From: Eric Newport Date: Sun, 15 Sep 2024 08:20:04 -0400 Subject: [PATCH 60/60] final edits --- CHANGELOG.md | 4 +-- README.md | 90 +++++++++++++++++++++++++++++++++------------- package-lock.json | 24 ++++++------- package.json | 14 +++++--- semanticForms.html | 8 ++--- 5 files changed, 93 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36cad94..b12ef63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# semanticforms changelog +# Semantic Forms changelog ## Next version @@ -6,7 +6,7 @@ ## 4.0.0 -- Breaking: Overhauled entire codebase to drive it using CSS grid instead of flexbox. This makes everything more flexible overall and fit more designs better. However the CSS and markup changes will likely cause breaking changes to previous integrations, so when upgrading make some time to visually test all your pages to alter any CSS overrides you had in place accordingly. You also might want to make some markup changes to make use of new available classes to tweak the fit of individual form fields on specific forms. +- Breaking: Overhauled entire codebase to drive it using mostly CSS grid instead of flexbox. This makes everything more flexible overall and fit more designs better. However the CSS and markup changes will likely cause breaking changes to previous integrations, so when upgrading make some time to visually test all your pages to alter any CSS overrides you had in place accordingly. You also might want to make some markup changes to make use of new available classes to tweak the fit of individual form fields on specific forms. - Altered fields to fit available space better at various screen sizes. - Added multiple utility classes that define how wide inputs will span in the responsive layout. - Added support for input type=image. diff --git a/README.md b/README.md index d3ae30b..ad4fa60 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,23 @@ [![npm](https://img.shields.io/npm/v/semantic-forms.svg)](https://www.npmjs.com/package/semantic-forms) -A pattern library of forms based on semantic HTML enhanced with a modern UX. +A pattern library of attractive forms for your website with the following design goals: + +- Attractive, modern float label visual design. +- Responsive layout based on modern CSS grid technique. +- Clear fields. +- Light and dark mode. +- Invalid field styling. +- Good accessibility. +- Semantic HTML (no div soup). +- Uses a progressive enhancement approach so that core functionality and most of the features still work with JavaScript disabled. +- Sets no global styles and is scoped by a single class name `semanticForms` applied to `` elements. +- No dependencies. See a [live demo here](https://kethinov.github.io/semanticforms/semanticForms.html). +This module was built and is maintained by the [Roosevelt web framework](https://github.com/rooseveltframework/roosevelt) [team](https://github.com/orgs/rooseveltframework/people), but it can be used independently of Roosevelt as well. + # Usage Include the `semanticForms.css` and `semanticForms.js` files from this repo into your project. @@ -18,14 +31,18 @@ Then apply the `semanticForms` class to your `` elements: ``` +Then apply the JavaScript enhancements: + +```javascript +window.semanticForms() +``` + Then the CSS/JS enhancements to your forms will apply automatically, assuming the markup structure you use is one of the supported patterns. -This library also monitors changes to the DOM and will enhance any additional `semanticForms` forms you insert, but the monitoring may not be perfect. If you want to re-scan for new forms to enhance manually, simply call `window.semanticForms()`. If you only want to reinitialize one form instead of all of them, call `window.semanticForms.reinitialize(formName)`. +If you make changes to the DOM after Semantic Forms is activated and want to activate any additional `semanticForms` forms you insert, you can re-scan for new forms by calling `window.semanticForms()` again. If you only want to reinitialize one form instead of all of them, call `window.semanticForms.reinitialize(formElement)`. # Features -Overview of pattern library features: - ## Float label inputs The float label input pattern is notoriously difficult to implement in a fashion that doesn't degrade HTML semantics or accessibility. This pattern library implements a solution that solves that problem. Your label doesn't need to be a sibling of your input like with other implementations. This implementation also has a custom clear button for each input. @@ -54,7 +71,7 @@ The float label input pattern is notoriously difficult to implement in a fashion ### Add help text -Include a label in the `
    ` element with a matching `for` attribute to place help text beneath the input. +Include a label in the `
    ` element with a matching `for` attribute to place help text beneath the input: ```html
    @@ -69,7 +86,12 @@ Include a label in the `
    ` element with a matching `for` attribute to place h ``` ## Responsive columns -You can limit the number of columns on your forms using the `colspan-#` class on a `
    ` element. Applying the class to a `
    ` will apply that styling to all nested `
    ` elements. + +This feature makes it so the form fields will grow, shrink, expand the number of columns, or reduce the number of columns based on how much space exists in the container. You can customize it by applying various `colspan-#` classes to various elements in the form markup structure. + +### Set number of columns for a group of forms + +You can limit the number of columns on your forms using the `colspan-#` class on a `
    ` element: ```html @@ -78,7 +100,7 @@ You can limit the number of columns on your forms using the `colspan-#` class on
    -
    +
    @@ -87,6 +109,8 @@ You can limit the number of columns on your forms using the `colspan-#` class on ``` +You can also apply the class to a `
    ` which will apply that styling to all nested `
    ` elements: + ```html
    @@ -96,7 +120,7 @@ You can limit the number of columns on your forms using the `colspan-#` class on
    -
    +
    @@ -108,7 +132,7 @@ You can limit the number of columns on your forms using the `colspan-#` class on
    -
    +
    @@ -117,8 +141,8 @@ You can limit the number of columns on your forms using the `colspan-#` class on ``` -### Specify input columns -You can specify the number of columns an input will span using the `colspan-#` class on the `
    ` element. The inputs are responsive and will shrink according to available space. Available numbered classes are `colspan-1` through `colspan-5`. +### Set number of columns a single input field takes up +You can specify the number of columns an input will span using the `colspan-#` class on the `
    ` element. The inputs are responsive and will shrink according to available space. Available numbered classes are `colspan-1` through `colspan-5`: ```html @@ -141,7 +165,7 @@ You can specify the number of columns an input will span using the `colspan-#` c ``` -`colspan-full` can also be used to force an input to take up the entire width of a form. +`colspan-full` can also be used to force an input to take up the entire width of a form: ```html
    @@ -163,8 +187,23 @@ You can specify the number of columns an input will span using the `colspan-#` c
    ``` -> #### Low flow `colspan-#` -> To apply `colspan-#` styles to lowFlow form inputs, you will need to manually wrap your `
    ` and `
    ` elements in a `
    `. +#### Set number of columns a single input field takes up on the low flow (JavaScript disabled flow) + +To apply `colspan-#` styles to low flow (JavaScript disabled flow) form inputs, you will need to manually wrap your `
    ` and `
    ` elements in a `
    `: + +```html +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +``` ## Button groups @@ -250,7 +289,7 @@ Not too different than other inputs: ## Validation styles -Inputs with the `required` attribution will result in a visual indicator (*) being added to its label. You can disable this indicator with the `data-no-asterisk` attribute on the label element: +Inputs with the `required` attribute will result in a visual indicator (*) being added to its label. You can disable this indicator with the `data-no-asterisk` attribute on the label element: ```html
    @@ -271,24 +310,25 @@ You can adjust the tooltip text of the asterisk with the `data-asterisk-text` at
    ``` -## Other features +## Dark mode + +To set the dark mode, apply an additional class of `dark` to your `
    ` elements to force the dark mode. + +## Low flow (JavaScript disabled) mode + +The low flow will be displayed if JS is disabled. -- Custom-styled select boxes with a custom drawn arrow graphic driven by SVG embedded in the CSS. -- Custom-styled submit buttons to match the aesthetic of the custom-styled forms. -- Required inputs add a red asterisk to their labels. -- Responsive: on wide screens, the forms split into multiple columns. On smaller screens, they collapse to a single column. -- Validation: Invalid inputs are styled automatically after the user leaves the form input. Validation styling may be added manually using the `invalid` class. -- Dark mode: apply an additional class of `dark` to your `` elements to use the dark mode. -- Low-flow mode that displays on old browsers, JS-disabled browsers, or can be activated manually by adding the `lowFlow` class to your `` element. The low-flow mode reverts the float label pattern to traditional labels and collapses the forms to single column mode, but preserves the other visual design enhancements driven purely by CSS. +You can also activate the low flow (JavaScript disabled) mode manually by adding the `lowFlow` class to your `` element. -See `semanticForms.html` or the [live demo](https://kethinov.github.io/semanticforms/semanticForms.html) for a full demo of all the markup patterns. +The low-flow mode reverts the float label pattern to traditional labels and doesn't include other JS-exclusive enhancements, but preserves the other visual design enhancements driven purely by CSS. # Contributing - Fork/clone this repo. - `npm ci` - Make your changes. If you want to alter the CSS, do the changes in the `.scss` files. - - `npm run watch` automatically compiles the CSS file after a change is detected in the SCSS file. - `npm run build`. The build step compiles the SCSS file into CSS. + - You can also run `npm run watch` automatically compiles the CSS file after a change is detected in the SCSS file. - Test your changes by opening `semanticForms.html` in your browser. + - If you want to test your work on an actual HTTP server, run `npm run dev` or `npm run d`. - Commit, push, open pull request. diff --git a/package-lock.json b/package-lock.json index 2ffe74f..cd5f2c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "nodemon": "~3.1.4", "sass": "1.78.0", "serve": "14.2.3", - "standard": "17.1.0" + "standard": "17.1.2" }, "funding": { "url": "https://www.paypal.com/donate/?hosted_button_id=2L2X8GRXZCGJ6" @@ -50,9 +50,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", "dev": true, "license": "MIT", "engines": { @@ -1555,9 +1555,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.35.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.2.tgz", - "integrity": "sha512-Rbj2R9zwP2GYNcIak4xoAMV57hrBh3hTaR0k7hVjwCQgryE/pw5px4b13EYjduOI0hfXyZhwBxaGpOTbWSGzKQ==", + "version": "7.36.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz", + "integrity": "sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA==", "dev": true, "license": "MIT", "dependencies": { @@ -4100,9 +4100,9 @@ } }, "node_modules/standard": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/standard/-/standard-17.1.0.tgz", - "integrity": "sha512-jaDqlNSzLtWYW4lvQmU0EnxWMUGQiwHasZl5ZEIwx3S/ijZDjZOzs1y1QqKwKs5vqnFpGtizo4NOYX2s0Voq/g==", + "version": "17.1.2", + "resolved": "https://registry.npmjs.org/standard/-/standard-17.1.2.tgz", + "integrity": "sha512-WLm12WoXveKkvnPnPnaFUUHuOB2cUdAsJ4AiGHL2G0UNMrcRAWY2WriQaV8IQ3oRmYr0AWUbLNr94ekYFAHOrA==", "dev": true, "funding": [ { @@ -4126,8 +4126,8 @@ "eslint-plugin-import": "^2.27.5", "eslint-plugin-n": "^15.7.0", "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-react": "^7.32.2", - "standard-engine": "^15.0.0", + "eslint-plugin-react": "^7.36.1", + "standard-engine": "^15.1.0", "version-guard": "^1.1.1" }, "bin": { diff --git a/package.json b/package.json index 702fb4e..8cf0fc6 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,20 @@ { "name": "semantic-forms", "description": "Semantic Forms", - "author": "Eric Newport ", + "author": "Roosevelt Framework Team ", + "contributors": [ + { + "name": "Contributors", + "url": "https://github.com/rooseveltframework/semantic-forms/graphs/contributors" + } + ], "version": "4.0.0", "files": [ "semanticForms.css", "semanticForms.js", "semanticForms.scss" ], - "homepage": "https://github.com/kethinov/semanticforms", + "homepage": "https://github.com/rooseveltframework/semantic-forms", "license": "CC-BY-4.0", "main": "semanticForms.js", "readmeFilename": "README.md", @@ -18,7 +24,7 @@ "nodemon": "~3.1.4", "sass": "1.78.0", "serve": "14.2.3", - "standard": "17.1.0" + "standard": "17.1.2" }, "scripts": { "test": "echo \"TODO: tests\"", @@ -33,7 +39,7 @@ }, "repository": { "type": "git", - "url": "git://github.com/kethinov/semanticforms.git" + "url": "git://github.com/rooseveltframework/semantic-forms.git" }, "keywords": [ "semantic", diff --git a/semanticForms.html b/semanticForms.html index 04c29d2..d1dbdd8 100644 --- a/semanticForms.html +++ b/semanticForms.html @@ -30,7 +30,7 @@

    Semantic Forms

    A pattern library of forms based on semantic HTML enhanced with a modern UX.

    -

    Default styling

    +

    High flow (JavaScript enabled) styling

    @@ -53,7 +53,7 @@

    Default styling

    - Fieldset legend (high flow, JS enabled) + Fieldset legend
    @@ -423,7 +423,7 @@

    Default styling

    -

    Low flow styling

    +

    Low flow (JavaScript disabled) styling

    Adding the lowFlow class to the form element removes all JS enhancements.

    @@ -446,7 +446,7 @@

    Low flow styling

    - Fieldset legend (low flow, JS disabled) + Fieldset legend